UI improvements

This commit is contained in:
IRBorisov 2023-08-08 23:04:21 +03:00
parent f6c51a3c5f
commit 0fe2360886
14 changed files with 59 additions and 46 deletions

View File

@ -6,14 +6,15 @@ import Button from './Button';
interface ModalProps {
title?: string
submitText?: string
readonly?: boolean
canSubmit?: boolean
hideWindow: () => void
onSubmit: () => void
onSubmit?: () => void
onCancel?: () => void
children: React.ReactNode
}
function Modal({ title, hideWindow, onSubmit, onCancel, canSubmit, children, submitText = 'Продолжить' }: ModalProps) {
function Modal({ title, hideWindow, onSubmit, readonly, onCancel, canSubmit, children, submitText = 'Продолжить' }: ModalProps) {
const ref = useRef(null);
useEscapeKey(hideWindow);
@ -24,29 +25,32 @@ function Modal({ title, hideWindow, onSubmit, onCancel, canSubmit, children, sub
const handleSubmit = () => {
hideWindow();
onSubmit();
if (onSubmit) onSubmit();
};
return (
<>
<div className='fixed top-0 left-0 z-50 w-full h-full opacity-50 clr-modal'>
</div>
<div ref={ref} className='fixed bottom-1/2 left-1/2 translate-y-1/2 -translate-x-1/2 px-6 py-4 flex flex-col w-fit h-fit z-[60] clr-card border shadow-md mb-[5rem]'>
<div
ref={ref}
className='fixed bottom-1/2 left-1/2 translate-y-1/2 -translate-x-1/2 px-6 py-4 flex flex-col w-fit max-w-[95vw] h-fit z-[60] clr-card border shadow-md mb-[5rem]'
>
{ title && <h1 className='mb-2 text-xl font-bold text-center'>{title}</h1> }
<div>
<div className='max-h-[calc(95vh-15rem)] overflow-auto'>
{children}
</div>
<div className='flex justify-between w-full pt-4 mt-2 border-t-4'>
<Button
<div className='flex justify-center w-full gap-4 pt-4 mt-2 border-t-4'>
{!readonly && <Button
text={submitText}
widthClass='min-w-[6rem] min-h-[2.6rem] w-fit h-fit'
colorClass='clr-btn-primary'
disabled={!canSubmit}
onClick={handleSubmit}
autoFocus
/>
/>}
<Button
text='Отмена'
text={readonly ? 'Закрыть' : 'Отмена'}
widthClass='min-w-[6rem] min-h-[2.6rem] w-fit h-fit'
onClick={handleCancel}
/>

View File

@ -8,7 +8,7 @@ interface SubmitButtonProps {
function SubmitButton({ text = 'ОК', icon, disabled, loading = false }: SubmitButtonProps) {
return (
<button type='submit'
className={`px-4 py-2 inline-flex items-center gap-2 align-middle justify-center font-bold disabled:cursor-not-allowed rounded clr-btn-primary ${loading ? ' cursor-progress' : ''}`}
className={`px-4 py-2 inline-flex items-center gap-2 align-middle justify-center font-bold disabled:cursor-not-allowed border rounded clr-btn-primary ${loading ? ' cursor-progress' : ''}`}
disabled={disabled ?? loading}
>
{icon && <span>{icon}</span>}

View File

@ -28,7 +28,7 @@ function TextArea({
htmlFor={id}
/>
<textarea id={id}
className={'px-3 py-2 mt-2 leading-tight border shadow dark:bg-gray-800 ' + widthClass}
className={`px-3 py-2 mt-2 leading-tight border shadow clr-input ${widthClass}`}
rows={rows}
placeholder={placeholder}
required={required}

View File

@ -21,7 +21,7 @@ function TextInput({
htmlFor={id}
/>
<input id={id}
className={'px-3 py-2 mt-2 leading-tight border shadow dark:bg-gray-800 truncate hover:text-clip ' + widthClass}
className={`px-3 py-2 mt-2 leading-tight border shadow truncate hover:text-clip clr-input ${widthClass}`}
required={required}
{...props}
/>

View File

@ -1,11 +1,13 @@
import { useNavigate } from 'react-router-dom';
import { toast } from 'react-toastify';
import { useAuth } from '../../context/AuthContext';
import { BellIcon, PlusIcon, SquaresIcon } from '../Icons';
import NavigationButton from './NavigationButton';
function UserTools() {
const navigate = useNavigate();
const { user } = useAuth();
const navigateCreateRSForm = () => { navigate('/rsform-create'); };
const navigateMyWork = () => { navigate('/library?filter=personal'); };
@ -24,7 +26,7 @@ function UserTools() {
/>
</span>
<NavigationButton icon={<SquaresIcon />} description='Мои схемы' onClick={navigateMyWork} />
<NavigationButton icon={<BellIcon />} description='Уведомления' onClick={handleNotifications} />
{ user && user.is_staff && <NavigationButton icon={<BellIcon />} description='Уведомления' onClick={handleNotifications} />}
</div>
);
}

View File

@ -87,7 +87,7 @@ export const RSFormState = ({ schemaID, children }: RSFormStateProps) => {
const toggleTracking = useCallback(
() => {
toast('not implemented yet')
toast.info('Отслеживание в разработке...')
}, [])
const update = useCallback(

View File

@ -51,6 +51,10 @@
@apply border-gray-400 dark:border-gray-300 bg-white dark:bg-gray-700
}
.clr-input {
@apply dark:bg-black bg-white disabled:bg-[#f0f2f7] dark:disabled:bg-gray-700
}
.clr-footer {
@apply text-gray-600 bg-white border-gray-400 dark:bg-gray-700 dark:border-gray-300 dark:text-gray-300
}
@ -68,11 +72,11 @@
}
.clr-btn-primary {
@apply text-white bg-blue-400 hover:bg-blue-600 dark:bg-orange-600 dark:hover:bg-orange-400 disabled:bg-gray-400 dark:disabled:bg-gray-400
@apply text-white bg-blue-400 hover:bg-blue-600 dark:bg-orange-600 dark:hover:bg-orange-400 disabled:bg-gray-400 dark:disabled:bg-gray-600
}
.clr-btn-default {
@apply text-gray-500 dark:text-zinc-200 dark:disabled:text-zinc-400 disabled:text-gray-400 bg-gray-100 hover:bg-gray-300 dark:bg-gray-600 dark:hover:bg-gray-400
@apply text-gray-600 dark:text-zinc-200 dark:disabled:text-zinc-400 disabled:text-gray-400 bg-[#f0f2f7] hover:bg-gray-300 dark:bg-gray-600 dark:hover:bg-gray-400
}
/* Transparent button */

View File

@ -1,3 +1,4 @@
import { useLayoutEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { useAuth } from '../context/AuthContext';
@ -5,11 +6,14 @@ import { useAuth } from '../context/AuthContext';
function HomePage() {
const navigate = useNavigate();
const { user } = useAuth();
if (!user) {
navigate('/library?filter=common');
} else if(!user.is_staff) {
navigate('/library?filter=personal');
}
useLayoutEffect(() => {
if (!user) {
navigate('/library?filter=common');
} else if(!user.is_staff) {
navigate('/library?filter=personal');
}
}, [navigate, user])
return (
<div className='flex flex-col items-center justify-center w-full py-2'>

View File

@ -16,10 +16,6 @@ interface DlgShowASTProps {
function DlgShowAST({ hideWindow, syntaxTree, expression }: DlgShowASTProps) {
const { darkMode } = useConceptTheme();
function handleSubmit() {
// Do nothing
}
const nodes: GraphNode[] = useMemo(
() => syntaxTree.map(node => {
return {
@ -46,14 +42,12 @@ function DlgShowAST({ hideWindow, syntaxTree, expression }: DlgShowASTProps) {
return (
<Modal
hideWindow={hideWindow}
onSubmit={handleSubmit}
submitText='Закрыть'
canSubmit={true}
readonly
>
<div className='flex flex-col items-start gap-2'>
<div className='w-full text-lg text-center'>{expression}</div>
<div className='flex-wrap w-full h-full overflow-auto'>
<div className='relative w-[1040px] h-[600px] 2xl:w-[1680px] 2xl:h-[600px]'>
<div className='relative w-[1040px] h-[600px] 2xl:w-[1680px] 2xl:h-[600px] max-h-full max-w-full'>
<GraphCanvas
nodes={nodes}
edges={edges}

View File

@ -114,7 +114,7 @@ function EditorConstituenta({ activeID, onShowAST, onCreateCst, onOpenEdit, onDe
<div className='flex items-start justify-between'>
<button type='submit'
title='Сохранить изменения'
className='px-1 py-1 font-bold rounded whitespace-nowrap disabled:cursor-not-allowed clr-btn-primary'
className='px-1 py-1 font-bold border rounded whitespace-nowrap disabled:cursor-not-allowed clr-btn-primary'
disabled={!isModified || !isEnabled}
>
<SaveIcon size={5} />
@ -166,7 +166,7 @@ function EditorConstituenta({ activeID, onShowAST, onCreateCst, onOpenEdit, onDe
<p>- слева от ввода текста настраивается набор атрибутов конституенты</p>
<p>- справа от ввода текста настраивается список конституент, которые фильтруются</p>
<p>- текущая конституента выделена цветом строки</p>
<p>- двойнок клин / Alt + клик - выбор редактируемой конституенты</p>
<p>- двойной клик / Alt + клик - выбор редактируемой конституенты</p>
<p>- при наведении на ID конституенты отображаются ее атрибуты</p>
<p>- столбец "Описание" содержит один из непустых текстовых атрибутов</p>
<Divider margins='mt-2' />

View File

@ -210,13 +210,22 @@ function EditorRSExpression({
return (
<div className='flex flex-col items-start [&:not(:first-child)]:mt-3 w-full'>
<div className='relative w-full'>
<div className='absolute top-[-0.3rem] right-0'>
<StatusBar
isModified={isModified}
constituenta={activeCst}
parseData={parseData}
/>
</div>
</div>
<Label
text={label}
required={false}
htmlFor={id}
/>
<textarea id={id} ref={expressionCtrl}
className='w-full px-3 py-2 mt-2 leading-tight border shadow dark:bg-gray-800'
className='w-full px-3 py-2 mt-2 leading-tight border shadow clr-input'
rows={6}
placeholder={placeholder}
value={value}
@ -228,23 +237,15 @@ function EditorRSExpression({
/>
<div className='flex w-full gap-4 py-1 mt-1 justify-stretch'>
<div className='flex flex-col gap-2'>
{isActive && <StatusBar
isModified={isModified}
constituenta={activeCst}
parseData={parseData}
/>}
<Button
tooltip='Проверить формальное выражение'
text='Проверить'
widthClass='h-full w-fit'
colorClass='clr-btn-default'
onClick={handleCheckExpression}
/>
</div>
{isActive && EditButtons}
{!isActive && <StatusBar
isModified={isModified}
constituenta={activeCst}
parseData={parseData}
/>}
</div>
{ (loading || parseData) &&
<div className='w-full overflow-y-auto border mt-2 max-h-[14rem] min-h-[7rem]'>

View File

@ -35,7 +35,7 @@ function MatchModePicker({ value, onChange }: MatchModePickerProps) {
<p><b>везде:</b> искать во всех атрибутах</p>
</DropdownButton>
<DropdownButton onClick={() => handleChange(CstMatchMode.EXPR)}>
<p><b>ФВ:</b> искать в формальных выражениях</p>
<p><b>выраж:</b> искать в формальных выражениях</p>
</DropdownButton>
<DropdownButton onClick={() => handleChange(CstMatchMode.TERM)}>
<p><b>термин:</b> искать в терминах</p>

View File

@ -24,8 +24,8 @@ function StatusBar({ isModified, constituenta, parseData }: StatusBarProps) {
const data = mapStatusInfo.get(status)!;
return (
<div title={data.tooltip}
className={'min-h-[2rem] min-w-[6rem] font-semibold inline-flex border rounded-lg items-center justify-center align-middle ' + data.color}>
{data.text}
className={`text-sm h-[1.6rem] w-[10rem] font-semibold inline-flex border items-center justify-center align-middle ${data.color}`}>
Статус: [ {data.text} ]
</div>
)
}

View File

@ -5,6 +5,10 @@ import { defineConfig } from 'vite'
export default defineConfig({
plugins: [react()],
server: {
port: 3000
port: 3000,
// https: {
// key: fs.readFileSync('cert/portal-key.pem'),
// cert: fs.readFileSync('cert/portal-cert.pem'),
// }
}
})