Minor UI improvements

This commit is contained in:
IRBorisov 2023-09-04 20:37:55 +03:00
parent 04c3531f60
commit a6b21279a9
7 changed files with 133 additions and 23 deletions

View File

@ -13,7 +13,7 @@ export interface CheckboxProps {
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void
}
function Checkbox({ id, required, disabled, tooltip, label, widthClass = 'w-full', value, onChange }: CheckboxProps) {
function Checkbox({ id, required, disabled, tooltip, label, widthClass = 'w-fit', value, onChange }: CheckboxProps) {
const inputRef = useRef<HTMLInputElement | null>(null);
const cursor = disabled ? 'cursor-not-allowed' : 'cursor-pointer';
@ -27,7 +27,7 @@ function Checkbox({ id, required, disabled, tooltip, label, widthClass = 'w-full
return (
<button
className={'flex gap-2 [&:not(:first-child)]:mt-3 ' + widthClass}
className={'flex [&:not(:first-child)]:mt-3 clr-outline focus:outline-dotted focus:outline-1 ' + widthClass}
title={tooltip}
disabled={disabled}
onClick={handleClick}
@ -42,7 +42,7 @@ function Checkbox({ id, required, disabled, tooltip, label, widthClass = 'w-full
/>
{ label &&
<Label
className={`${cursor}`}
className={`${cursor} px-2`}
text={label}
required={required}
htmlFor={id}

View File

@ -15,7 +15,7 @@ interface FileInputProps {
function FileInput({ id, required, label, acceptType, widthClass = 'w-full', onChange }: FileInputProps) {
const inputRef = useRef<HTMLInputElement | null>(null);
const [labelText, setLabelText] = useState('Файл не выбран');
const [labelText, setLabelText] = useState('');
const handleUploadClick = () => {
inputRef.current?.click();
@ -25,7 +25,7 @@ function FileInput({ id, required, label, acceptType, widthClass = 'w-full', onC
if (event.target.files && event.target.files.length > 0) {
setLabelText(event.target.files[0].name)
} else {
setLabelText('Файл не выбран')
setLabelText('')
}
if (onChange) {
onChange(event);

View File

@ -189,7 +189,9 @@
}
}
:is(.clr-outline
:is(.clr-outline,
.clr-btn-default,
.clr-btn-primary
):focus {
outline-width: 2px;
outline-style: solid;

View File

@ -94,7 +94,7 @@ function CreateRSFormPage() {
value={common}
onChange={event => setCommon(event.target.checked)}
/>
<FileInput id='trs' label='Загрузить *.trs'
<FileInput id='trs' label='Загрузить из Экстеор'
acceptType='.trs'
onChange={handleFile}
/>

View File

@ -1,11 +1,12 @@
import { useMemo } from 'react';
import { darkTheme, GraphCanvas, GraphEdge, GraphNode, lightTheme } from 'reagraph';
import { useCallback, useMemo, useState } from 'react';
import { GraphCanvas,GraphEdge, GraphNode } from 'reagraph';
import Modal from '../../components/Common/Modal';
import { useConceptTheme } from '../../context/ThemeContext';
import { graphDarkT, graphLightT } from '../../utils/color';
import { resources } from '../../utils/constants';
import { SyntaxTree } from '../../utils/models';
import { getNodeLabel } from '../../utils/staticUI';
import { getASTNodeColor, getASTNodeLabel } from '../../utils/staticUI';
interface DlgShowASTProps {
hideWindow: () => void
@ -14,15 +15,21 @@ interface DlgShowASTProps {
}
function DlgShowAST({ hideWindow, syntaxTree, expression }: DlgShowASTProps) {
const { darkMode } = useConceptTheme();
const { darkMode, colors } = useConceptTheme();
const [hoverID, setHoverID] = useState<number | undefined>(undefined);
const hoverNode = useMemo(
() => {
return syntaxTree.find(node => node.uid === hoverID);
}, [hoverID, syntaxTree]);
const nodes: GraphNode[] = useMemo(
() => syntaxTree.map(node => {
return {
id: String(node.uid),
label: getNodeLabel(node)
label: getASTNodeLabel(node),
fill: getASTNodeColor(node, colors),
};
}), [syntaxTree]);
}), [syntaxTree, colors]);
const edges: GraphEdge[] = useMemo(
() => {
@ -39,13 +46,32 @@ function DlgShowAST({ hideWindow, syntaxTree, expression }: DlgShowASTProps) {
return result;
}, [syntaxTree]);
const handleHoverIn = useCallback(
(node: GraphNode) => {
setHoverID(Number(node.id));
}, []);
const handleHoverOut = useCallback(
() => {
setHoverID(undefined);
}, []);
return (
<Modal
hideWindow={hideWindow}
readonly
>
<div className='flex flex-col items-start gap-2'>
<div className='w-full text-lg text-center'>{expression}</div>
<div className='w-full text-lg text-center'>
{!hoverNode && expression}
{hoverNode &&
<div className='flex justify-center whitespace-pre'>
<span>{expression.slice(0, hoverNode.start)}</span>
<span className='clr-selected'>{expression.slice(hoverNode.start, hoverNode.finish)}</span>
<span>{expression.slice(hoverNode.finish)}</span>
</div>
}
</div>
<div className='flex-wrap w-full h-full overflow-auto'>
<div className='relative w-[1040px] h-[600px] 2xl:w-[1680px] 2xl:h-[600px] max-h-full max-w-full'>
<GraphCanvas
@ -53,7 +79,9 @@ function DlgShowAST({ hideWindow, syntaxTree, expression }: DlgShowASTProps) {
edges={edges}
layoutType='hierarchicalTd'
labelFontUrl={resources.graph_font}
theme={darkMode ? darkTheme : lightTheme}
theme={darkMode ? graphDarkT : graphLightT}
onNodePointerOver={handleHoverIn}
onNodePointerOut={handleHoverOut}
/>
</div>
</div>

View File

@ -222,7 +222,7 @@ function EditorRSExpression({
{ !loading && parseData &&
<ParsingResult
data={parseData}
onShowAST={ast => onShowAST(value, ast)}
onShowAST={ast => onShowAST(getCstExpressionPrefix(activeCst!) + value, ast)}
onShowError={onShowError}
/>}
{ !loading && !parseData &&

View File

@ -598,13 +598,14 @@ export function getRSErrorMessage(error: IRSErrorDescription): string {
return 'UNKNOWN ERROR';
}
export function getNodeLabel(node: ISyntaxTreeNode): string {
export function getASTNodeLabel(node: ISyntaxTreeNode): string {
switch(node.typeID) {
case TokenID.ID_LOCAL: return node.data.value as string;
case TokenID.ID_GLOBAL: return node.data.value as string;
case TokenID.ID_FUNCTION: return node.data.value as string;
case TokenID.ID_PREDICATE: return node.data.value as string;
case TokenID.ID_RADICAL: return node.data.value as string;
case TokenID.ID_LOCAL:
case TokenID.ID_GLOBAL:
case TokenID.ID_FUNCTION:
case TokenID.ID_PREDICATE:
case TokenID.ID_RADICAL:
return node.data.value as string;
case TokenID.LIT_INTEGER: return String(node.data.value as number);
@ -675,3 +676,82 @@ export function getNodeLabel(node: ISyntaxTreeNode): string {
// node
return 'UNKNOWN ' + String(node.typeID);
}
export function getASTNodeColor(node: ISyntaxTreeNode, colors: IColorTheme): string {
switch(node.typeID) {
case TokenID.PUNC_DEFINE:
case TokenID.PUNC_STRUCT:
case TokenID.ID_LOCAL:
return colors.green;
case TokenID.ID_GLOBAL:
case TokenID.ID_FUNCTION:
case TokenID.ID_PREDICATE:
case TokenID.ID_RADICAL:
case TokenID.LIT_INTEGER:
case TokenID.LIT_EMPTYSET:
case TokenID.LIT_INTSET:
return colors.teal;
case TokenID.FORALL:
case TokenID.EXISTS:
case TokenID.NOT:
case TokenID.AND:
case TokenID.OR:
case TokenID.IMPLICATION:
case TokenID.EQUIVALENT:
case TokenID.GREATER:
case TokenID.LESSER:
case TokenID.EQUAL:
case TokenID.NOTEQUAL:
case TokenID.GREATER_OR_EQ:
case TokenID.LESSER_OR_EQ:
case TokenID.IN:
case TokenID.NOTIN:
case TokenID.SUBSET_OR_EQ:
case TokenID.SUBSET:
case TokenID.NOTSUBSET:
return colors.orange;
case TokenID.NT_TUPLE:
case TokenID.NT_ENUMERATION:
case TokenID.BIGPR:
case TokenID.SMALLPR:
case TokenID.FILTER:
case TokenID.PLUS:
case TokenID.MINUS:
case TokenID.MULTIPLY:
case TokenID.BOOLEAN:
case TokenID.DECART:
case TokenID.INTERSECTION:
case TokenID.UNION:
case TokenID.SET_MINUS:
case TokenID.SYMMINUS:
case TokenID.REDUCE:
case TokenID.CARD:
case TokenID.BOOL:
case TokenID.DEBOOL:
return colors.blue;
case TokenID.NT_FUNC_DEFINITION:
case TokenID.NT_DECLARATIVE_EXPR:
case TokenID.NT_IMPERATIVE_EXPR:
case TokenID.NT_RECURSIVE_FULL:
case TokenID.NT_ENUM_DECL:
case TokenID.NT_TUPLE_DECL:
case TokenID.NT_ARG_DECL:
case TokenID.NT_FUNC_CALL:
case TokenID.NT_ARGUMENTS:
case TokenID.NT_IMP_DECLARE:
case TokenID.NT_IMP_ASSIGN:
case TokenID.NT_IMP_LOGIC:
case TokenID.NT_RECURSIVE_SHORT:
return '';
case TokenID.PUNC_ASSIGN:
case TokenID.PUNC_ITERATE:
return colors.red;
}
// node
return colors.red;
}