mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 04:50:36 +03:00
Minor UI improvements
This commit is contained in:
parent
6e1460a827
commit
2d3403bb84
|
@ -7,17 +7,19 @@ function HelpConstituenta() {
|
|||
<div className='leading-tight'>
|
||||
<h1>Редактор конституент</h1>
|
||||
<p><b>Сохранить изменения</b>: Ctrl + S или клик по кнопке Сохранить</p>
|
||||
<p className='mt-1'><b>Формальное определение</b>: обратите внимание на кнопки снизу<br/>Горячие клавиши указаны в подсказках при наведении</p>
|
||||
<p className='mt-1'><b>Поля Термин и Определение</b>: Ctrl + Пробел открывает диалог редактирования отсылок<br/>Перед открытием диалога переместите текстовый курсор на заменяемое слово или ссылку</p>
|
||||
<p className='mt-1'><b>Формальное определение</b></p>
|
||||
<p>- Ctrl + Пробел после ввода первой буквы дополняет до незанятого имени</p>
|
||||
<p>- специальные конструкции вводятся с помощью кнопок снизу</p>
|
||||
<p className='mt-1'><b>Термин и Определение</b>: Ctrl + Пробел открывает диалог редактирования отсылок<br/>Перед открытием диалога переместите текстовый курсор на заменяемое слово или ссылку</p>
|
||||
<p className='mt-1'><b>Список конституент справа</b>: обратите внимание на настройки фильтрации</p>
|
||||
<p>- первая настройка - атрибуты конституенты</p>
|
||||
<p>- вторая настройка - принцип отбора конституент по графу термов</p>
|
||||
<p>- текущая конституента выделена цветом строки</p>
|
||||
<p>- текущая конституента выделена цветом</p>
|
||||
<p>- двойной клик / Alt + клик - выбор редактируемой конституенты</p>
|
||||
<p>- при наведении на имя конституенты отображаются ее атрибуты</p>
|
||||
<p>- столбец "Описание" содержит один из непустых текстовых атрибутов</p>
|
||||
|
||||
<Divider margins='mt-4' />
|
||||
<Divider margins='my-2' />
|
||||
|
||||
<InfoCstStatus title='Статусы' />
|
||||
</div>);
|
||||
|
|
|
@ -11,6 +11,8 @@ import { forwardRef, useCallback, useMemo, useRef } from 'react';
|
|||
import Label from '@/components/ui/Label';
|
||||
import { useRSForm } from '@/context/RSFormContext';
|
||||
import { useConceptTheme } from '@/context/ThemeContext';
|
||||
import { generateAlias, getCstTypePrefix, guessCstType } from '@/models/rsformAPI';
|
||||
import { extractGlobals } from '@/models/rslangAPI';
|
||||
|
||||
import { ccBracketMatching } from './bracketMatching';
|
||||
import { RSLanguage } from './rslang';
|
||||
|
@ -106,7 +108,22 @@ const RSInput = forwardRef<ReactCodeMirrorRef, RSInputProps>(
|
|||
return;
|
||||
}
|
||||
const text = new RSTextWrapper(thisRef.current as Required<ReactCodeMirrorRef>);
|
||||
if (event.altKey) {
|
||||
if (event.ctrlKey && event.code === 'Space') {
|
||||
const selection = text.getSelection();
|
||||
if (!selection.empty || !schema) {
|
||||
return;
|
||||
}
|
||||
const hint = text.getText(selection.from - 1, selection.from);
|
||||
const type = guessCstType(hint);
|
||||
if (hint === getCstTypePrefix(type)) {
|
||||
text.setSelection(selection.from - 1, selection.from);
|
||||
}
|
||||
const takenAliases = [...extractGlobals(thisRef.current.view?.state.doc.toString() ?? '')];
|
||||
const newAlias = generateAlias(type, schema, takenAliases);
|
||||
text.replaceWith(newAlias);
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
} else if (event.altKey) {
|
||||
if (text.processAltKey(event.code, event.shiftKey)) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
@ -124,7 +141,7 @@ const RSInput = forwardRef<ReactCodeMirrorRef, RSInputProps>(
|
|||
event.stopPropagation();
|
||||
}
|
||||
},
|
||||
[thisRef, onAnalyze]
|
||||
[thisRef, onAnalyze, schema]
|
||||
);
|
||||
|
||||
return (
|
||||
|
|
|
@ -244,6 +244,27 @@ export function getCstTypePrefix(type: CstType) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Guess {@link CstType} from user input hint.
|
||||
*/
|
||||
export function guessCstType(hint: string, defaultType: CstType = CstType.TERM) {
|
||||
if (hint.length !== 1) {
|
||||
return defaultType;
|
||||
}
|
||||
// prettier-ignore
|
||||
switch (hint) {
|
||||
case 'X': return CstType.BASE;
|
||||
case 'C': return CstType.CONSTANT;
|
||||
case 'S': return CstType.STRUCTURED;
|
||||
case 'A': return CstType.AXIOM;
|
||||
case 'D': return CstType.TERM;
|
||||
case 'F': return CstType.FUNCTION;
|
||||
case 'P': return CstType.PREDICATE;
|
||||
case 'T': return CstType.THEOREM;
|
||||
}
|
||||
return defaultType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate new alias against {@link CstType} and {@link IRSForm}.
|
||||
*/
|
||||
|
@ -261,17 +282,22 @@ export function getDefinitionPrefix(cst: IConstituenta): string {
|
|||
/**
|
||||
* Generate alias for new {@link IConstituenta} of a given {@link CstType} for current {@link IRSForm}.
|
||||
*/
|
||||
export function generateAlias(type: CstType, schema: IRSForm): string {
|
||||
export function generateAlias(type: CstType, schema: IRSForm, takenAliases: string[] = []): string {
|
||||
const prefix = getCstTypePrefix(type);
|
||||
if (!schema.items || schema.items.length <= 0) {
|
||||
return `${prefix}1`;
|
||||
}
|
||||
const index = schema.items.reduce((prev, cst, index) => {
|
||||
let index = schema.items.reduce((prev, cst, index) => {
|
||||
if (cst.cst_type !== type) {
|
||||
return prev;
|
||||
}
|
||||
index = Number(cst.alias.slice(1 - cst.alias.length)) + 1;
|
||||
return Math.max(prev, index);
|
||||
}, 1);
|
||||
return `${prefix}${index}`;
|
||||
let alias = `${prefix}${index}`;
|
||||
while (takenAliases.includes(alias)) {
|
||||
index = index + 1;
|
||||
alias = `${prefix}${index}`;
|
||||
}
|
||||
return alias;
|
||||
}
|
||||
|
|
|
@ -88,7 +88,7 @@ function FormRSForm({ id, disabled, isModified, setIsModified }: FormRSFormProps
|
|||
return (
|
||||
<form
|
||||
id={id}
|
||||
className={clsx('mt-1 min-w-[22rem] w-full sm:max-w-[30rem]', 'py-1', classnames.flex_col)}
|
||||
className={clsx('mt-1 min-w-[22rem] sm:w-[30rem]', 'py-1', classnames.flex_col)}
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
<TextInput
|
||||
|
|
Loading…
Reference in New Issue
Block a user