Small screen optimizations and help fix

This commit is contained in:
IRBorisov 2024-05-30 01:04:25 +03:00
parent 26991f460c
commit 64e1b028bc
12 changed files with 146 additions and 71 deletions

View File

@ -11,7 +11,7 @@ function ApplicationLayout() {
const { viewportHeight, mainHeight, showScroll } = useConceptOptions(); const { viewportHeight, mainHeight, showScroll } = useConceptOptions();
return ( return (
<NavigationState> <NavigationState>
<div className='min-w-[20rem] clr-app antialiased'> <div className='min-w-[20rem] overflow-x-auto max-w-[100vw] clr-app antialiased'>
<ConceptToaster <ConceptToaster
className='mt-[4rem] text-sm' // prettier: split lines className='mt-[4rem] text-sm' // prettier: split lines
autoClose={3000} autoClose={3000}
@ -23,7 +23,7 @@ function ApplicationLayout() {
<div <div
id={globals.main_scroll} id={globals.main_scroll}
className='overflow-x-auto cc-scroll-y min-w-fit' className='cc-scroll-y min-w-fit'
style={{ style={{
maxHeight: viewportHeight, maxHeight: viewportHeight,
overflowY: showScroll ? 'scroll' : 'auto' overflowY: showScroll ? 'scroll' : 'auto'

View File

@ -1,16 +1,21 @@
import LinkTopic from '@/components/ui/LinkTopic';
import { useConceptOptions } from '@/context/OptionsContext';
import { HelpTopic } from '@/models/miscellaneous';
import { import {
IconClone,
IconControls, IconControls,
IconDestroy,
IconEdit, IconEdit,
IconList, IconList,
IconMoveDown,
IconMoveUp,
IconNewItem,
IconReset,
IconSave, IconSave,
IconStatusOK, IconStatusOK,
IconText, IconText,
IconTree IconTree
} from '../../../components/Icons'; } from '@/components/Icons';
import LinkTopic from '@/components/ui/LinkTopic';
import { useConceptOptions } from '@/context/OptionsContext';
import { HelpTopic } from '@/models/miscellaneous';
function HelpCstEditor() { function HelpCstEditor() {
const { colors } = useConceptOptions(); const { colors } = useConceptOptions();
@ -21,11 +26,23 @@ function HelpCstEditor() {
<IconSave className='inline-icon' /> сохранить изменения: Ctrl + S <IconSave className='inline-icon' /> сохранить изменения: Ctrl + S
</li> </li>
<li> <li>
<IconEdit className='inline-icon' /> кнопка переименования справа от{' '} <IconReset className='inline-icon' /> сбросить несохраненные изменения
<LinkTopic text='Имени' topic={HelpTopic.CC_CONSTITUENTA} /> </li>
<li>
<IconClone className='inline-icon icon-green' /> клонировать текущую: Alt + V
</li>
<li>
<IconNewItem className='inline-icon icon-green' /> новая конституента
</li>
<li>
<IconDestroy className='inline-icon icon-red' /> удаление текущей
</li> </li>
<h2>Термин и Текстовое определение</h2> <h2>Термин и Текстовое определение</h2>
<li>
<IconEdit className='inline-icon' /> кнопка переименования справа от{' '}
<LinkTopic text='Имени' topic={HelpTopic.CC_CONSTITUENTA} />
</li>
<li> <li>
<IconEdit className='inline-icon' /> кнопка редактирования словоформ справа от{' '} <IconEdit className='inline-icon' /> кнопка редактирования словоформ справа от{' '}
<LinkTopic text='Термина' topic={HelpTopic.CC_CONSTITUENTA} /> <LinkTopic text='Термина' topic={HelpTopic.CC_CONSTITUENTA} />
@ -42,9 +59,6 @@ function HelpCstEditor() {
<li> <li>
<IconControls className='inline-icon' /> специальная клавиатура и горячие клавиши <IconControls className='inline-icon' /> специальная клавиатура и горячие клавиши
</li> </li>
<li>
<IconList className='inline-icon' /> отображение списка конституент
</li>
<li> <li>
<IconTree className='inline-icon' /> отображение{' '} <IconTree className='inline-icon' /> отображение{' '}
<LinkTopic text='дерева разбора' topic={HelpTopic.UI_FORMULA_TREE} /> <LinkTopic text='дерева разбора' topic={HelpTopic.UI_FORMULA_TREE} />
@ -52,6 +66,13 @@ function HelpCstEditor() {
<li>Ctrl + Пробел дополняет до незанятого имени</li> <li>Ctrl + Пробел дополняет до незанятого имени</li>
<h2>Список конституент</h2> <h2>Список конституент</h2>
<li>
<IconList className='inline-icon' /> отображение списка конституент
</li>
<li>
<IconMoveDown className='inline-icon' />
<IconMoveUp className='inline-icon' /> Alt + вверх/вниз перемещение
</li>
<li>фильтрация в верхней части</li> <li>фильтрация в верхней части</li>
<li>при наведении на имя конституенты отображаются атрибуты</li> <li>при наведении на имя конституенты отображаются атрибуты</li>
<li> <li>

View File

@ -2,7 +2,16 @@ import InfoCstStatus from '@/components/info/InfoCstStatus';
import Divider from '@/components/ui/Divider'; import Divider from '@/components/ui/Divider';
import { HelpTopic } from '@/models/miscellaneous'; import { HelpTopic } from '@/models/miscellaneous';
import { IconAlias, IconDestroy, IconMoveDown, IconMoveUp, IconOpenList, IconReset } from '../../../components/Icons'; import {
IconAlias,
IconClone,
IconDestroy,
IconMoveDown,
IconMoveUp,
IconNewItem,
IconOpenList,
IconReset
} from '../../../components/Icons';
import LinkTopic from '../../../components/ui/LinkTopic'; import LinkTopic from '../../../components/ui/LinkTopic';
function HelpRSFormItems() { function HelpRSFormItems() {
@ -26,11 +35,18 @@ function HelpRSFormItems() {
<IconMoveUp className='inline-icon' /> <IconMoveUp className='inline-icon' />
<IconMoveDown className='inline-icon' /> Alt + вверх/вниз перемещение <IconMoveDown className='inline-icon' /> Alt + вверх/вниз перемещение
</li> </li>
<li> <li>
<IconDestroy className='inline-icon icon-red' /> удаление: Delete <IconClone className='inline-icon icon-green' /> клонировать выделенную: Alt + V
</li> </li>
<li> <li>
<IconOpenList className='inline-icon icon-green' /> добавление: Alt + 1-6,Q,W {' '} <IconNewItem className='inline-icon icon-green' /> новая конституента: Alt + `
</li>
<li>
<IconOpenList className='inline-icon icon-green' /> быстрое добавление: Alt + 1-6,Q,W
</li>
<li>
<IconDestroy className='inline-icon icon-red' /> удаление выделенных: Delete
</li> </li>
<Divider margins='my-2' /> <Divider margins='my-2' />

View File

@ -1,4 +1,14 @@
import { IconClone, IconDestroy, IconMoveDown, IconMoveUp, IconNewItem, IconReset, IconSave } from '@/components/Icons'; import {
IconClone,
IconDestroy,
IconList,
IconListOff,
IconMoveDown,
IconMoveUp,
IconNewItem,
IconReset,
IconSave
} from '@/components/Icons';
import BadgeHelp from '@/components/info/BadgeHelp'; import BadgeHelp from '@/components/info/BadgeHelp';
import MiniButton from '@/components/ui/MiniButton'; import MiniButton from '@/components/ui/MiniButton';
import Overlay from '@/components/ui/Overlay'; import Overlay from '@/components/ui/Overlay';
@ -8,6 +18,7 @@ import { messages, prepareTooltip } from '@/utils/labels';
interface ConstituentaToolbarProps { interface ConstituentaToolbarProps {
disabled: boolean; disabled: boolean;
modified: boolean; modified: boolean;
showList: boolean;
onSubmit: () => void; onSubmit: () => void;
onReset: () => void; onReset: () => void;
@ -17,18 +28,22 @@ interface ConstituentaToolbarProps {
onDelete: () => void; onDelete: () => void;
onClone: () => void; onClone: () => void;
onCreate: () => void; onCreate: () => void;
onToggleList: () => void;
} }
function ConstituentaToolbar({ function ConstituentaToolbar({
disabled, disabled,
modified, modified,
showList,
onSubmit, onSubmit,
onReset, onReset,
onMoveUp, onMoveUp,
onMoveDown, onMoveDown,
onDelete, onDelete,
onClone, onClone,
onCreate onCreate,
onToggleList
}: ConstituentaToolbarProps) { }: ConstituentaToolbarProps) {
return ( return (
<Overlay position='top-1 right-4' className='cc-icons sm:right-1/2 sm:translate-x-1/2'> <Overlay position='top-1 right-4' className='cc-icons sm:right-1/2 sm:translate-x-1/2'>
@ -62,6 +77,11 @@ function ConstituentaToolbar({
onClick={onDelete} onClick={onDelete}
icon={<IconDestroy size='1.25rem' className='icon-red' />} icon={<IconDestroy size='1.25rem' className='icon-red' />}
/> />
<MiniButton
title='Отображение списка конституент'
icon={showList ? <IconList size='1.25rem' className='icon-primary' /> : <IconListOff size='1.25rem' />}
onClick={onToggleList}
/>
<MiniButton <MiniButton
titleHtml={prepareTooltip('Переместить вверх', 'Alt + вверх')} titleHtml={prepareTooltip('Переместить вверх', 'Alt + вверх')}
icon={<IconMoveUp size='1.25rem' className='icon-primary' />} icon={<IconMoveUp size='1.25rem' className='icon-primary' />}

View File

@ -18,7 +18,7 @@ interface ControlsOverlayProps {
function ControlsOverlay({ constituenta, disabled, modified, processing, onRename, onEditTerm }: ControlsOverlayProps) { function ControlsOverlay({ constituenta, disabled, modified, processing, onRename, onEditTerm }: ControlsOverlayProps) {
return ( return (
<Overlay position='top-1 left-[4.3rem]' className='flex select-none'> <Overlay position='top-1 left-[4.7rem]' className='flex select-none'>
{!disabled || processing ? ( {!disabled || processing ? (
<MiniButton <MiniButton
title={modified ? messages.unsaved : `Редактировать словоформы термина`} title={modified ? messages.unsaved : `Редактировать словоформы термина`}

View File

@ -81,6 +81,7 @@ function EditorConstituenta({ activeCst, isModified, setIsModified, onOpenEdit }
<ConstituentaToolbar <ConstituentaToolbar
disabled={disabled} disabled={disabled}
modified={isModified} modified={isModified}
showList={showList}
onMoveUp={controller.moveUp} onMoveUp={controller.moveUp}
onMoveDown={controller.moveDown} onMoveDown={controller.moveDown}
onSubmit={initiateSubmit} onSubmit={initiateSubmit}
@ -88,6 +89,7 @@ function EditorConstituenta({ activeCst, isModified, setIsModified, onOpenEdit }
onDelete={controller.deleteCst} onDelete={controller.deleteCst}
onClone={controller.cloneCst} onClone={controller.cloneCst}
onCreate={() => controller.createCst(activeCst?.cst_type, false)} onCreate={() => controller.createCst(activeCst?.cst_type, false)}
onToggleList={() => setShowList(prev => !prev)}
/> />
) : null} ) : null}
<div <div
@ -101,12 +103,10 @@ function EditorConstituenta({ activeCst, isModified, setIsModified, onOpenEdit }
> >
<FormConstituenta <FormConstituenta
disabled={disabled} disabled={disabled}
showList={showList}
id={globals.constituenta_editor} id={globals.constituenta_editor}
state={activeCst} state={activeCst}
isModified={isModified} isModified={isModified}
toggleReset={toggleReset} toggleReset={toggleReset}
onToggleList={() => setShowList(prev => !prev)}
setIsModified={setIsModified} setIsModified={setIsModified}
onEditTerm={controller.editTermForms} onEditTerm={controller.editTermForms}
onRename={controller.renameCst} onRename={controller.renameCst}

View File

@ -25,7 +25,6 @@ export const ROW_SIZE_IN_CHARACTERS = 70;
interface FormConstituentaProps { interface FormConstituentaProps {
disabled: boolean; disabled: boolean;
showList: boolean;
id?: string; id?: string;
state?: IConstituenta; state?: IConstituenta;
@ -34,14 +33,12 @@ interface FormConstituentaProps {
toggleReset: boolean; toggleReset: boolean;
setIsModified: React.Dispatch<React.SetStateAction<boolean>>; setIsModified: React.Dispatch<React.SetStateAction<boolean>>;
onToggleList: () => void;
onRename: () => void; onRename: () => void;
onEditTerm: () => void; onEditTerm: () => void;
} }
function FormConstituenta({ function FormConstituenta({
disabled, disabled,
showList,
id, id,
state, state,
@ -50,8 +47,7 @@ function FormConstituenta({
toggleReset, toggleReset,
onRename, onRename,
onEditTerm, onEditTerm
onToggleList
}: FormConstituentaProps) { }: FormConstituentaProps) {
const { schema, cstUpdate, processing } = useRSForm(); const { schema, cstUpdate, processing } = useRSForm();
@ -138,7 +134,7 @@ function FormConstituenta({
/> />
<form <form
id={id} id={id}
className={clsx('cc-column', 'mt-1 w-full md:w-[47.8rem] shrink-0', 'px-4 py-1')} className={clsx('cc-column', 'mt-1 w-full md:w-[48.8rem] shrink-0', 'px-6 py-1')}
onSubmit={handleSubmit} onSubmit={handleSubmit}
> >
<RefsInput <RefsInput
@ -183,10 +179,8 @@ function FormConstituenta({
} }
value={expression} value={expression}
activeCst={state} activeCst={state}
showList={showList}
disabled={disabled} disabled={disabled}
toggleReset={toggleReset} toggleReset={toggleReset}
onToggleList={onToggleList}
onChange={newValue => setExpression(newValue)} onChange={newValue => setExpression(newValue)}
setTypification={setTypification} setTypification={setTypification}
/> />

View File

@ -5,13 +5,10 @@ import { AnimatePresence } from 'framer-motion';
import { useCallback, useLayoutEffect, useMemo, useRef, useState } from 'react'; import { useCallback, useLayoutEffect, useMemo, useRef, useState } from 'react';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import { IconControls, IconList, IconListOff, IconText, IconTextOff, IconTree } from '@/components/Icons';
import BadgeHelp from '@/components/info/BadgeHelp'; import BadgeHelp from '@/components/info/BadgeHelp';
import RSInput from '@/components/RSInput'; import RSInput from '@/components/RSInput';
import { RSTextWrapper } from '@/components/RSInput/textEditing'; import { RSTextWrapper } from '@/components/RSInput/textEditing';
import MiniButton from '@/components/ui/MiniButton';
import Overlay from '@/components/ui/Overlay'; import Overlay from '@/components/ui/Overlay';
import { useConceptOptions } from '@/context/OptionsContext';
import { useRSForm } from '@/context/RSFormContext'; import { useRSForm } from '@/context/RSFormContext';
import DlgShowAST from '@/dialogs/DlgShowAST'; import DlgShowAST from '@/dialogs/DlgShowAST';
import useCheckExpression from '@/hooks/useCheckExpression'; import useCheckExpression from '@/hooks/useCheckExpression';
@ -24,6 +21,7 @@ import { TokenID } from '@/models/rslang';
import { storage } from '@/utils/constants'; import { storage } from '@/utils/constants';
import { labelTypification } from '@/utils/labels'; import { labelTypification } from '@/utils/labels';
import ExpressionToolbar from './ExpressionToolbar';
import ParsingResult from './ParsingResult'; import ParsingResult from './ParsingResult';
import RSEditorControls from './RSEditControls'; import RSEditorControls from './RSEditControls';
import StatusBar from './StatusBar'; import StatusBar from './StatusBar';
@ -37,11 +35,9 @@ interface EditorRSExpressionProps {
disabled?: boolean; disabled?: boolean;
toggleReset?: boolean; toggleReset?: boolean;
showList: boolean;
setTypification: (typification: string) => void; setTypification: (typification: string) => void;
onChange: (newValue: string) => void; onChange: (newValue: string) => void;
onToggleList: () => void;
} }
function EditorRSExpression({ function EditorRSExpression({
@ -49,14 +45,11 @@ function EditorRSExpression({
disabled, disabled,
value, value,
toggleReset, toggleReset,
showList,
setTypification, setTypification,
onChange, onChange,
onToggleList,
...restProps ...restProps
}: EditorRSExpressionProps) { }: EditorRSExpressionProps) {
const model = useRSForm(); const model = useRSForm();
const { mathFont, setMathFont } = useConceptOptions();
const [isModified, setIsModified] = useState(false); const [isModified, setIsModified] = useState(false);
const parser = useCheckExpression({ schema: model.schema }); const parser = useCheckExpression({ schema: model.schema });
@ -147,10 +140,6 @@ function EditorRSExpression({
}); });
} }
function toggleFont() {
setMathFont(mathFont === 'math' ? 'math2' : 'math');
}
const controls = useMemo( const controls = useMemo(
() => ( () => (
<RSEditorControls <RSEditorControls
@ -170,32 +159,12 @@ function EditorRSExpression({
) : null} ) : null}
</AnimatePresence> </AnimatePresence>
<Overlay position='top-[-0.5rem] right-0 cc-icons'> <ExpressionToolbar
<MiniButton disabled={disabled}
title='Изменить шрифт' showControls={showControls}
onClick={toggleFont} showAST={handleShowAST}
icon={ toggleControls={() => setShowControls(prev => !prev)}
mathFont === 'math' ? <IconText size='1.25rem' className='icon-primary' /> : <IconTextOff size='1.25rem' />
}
/> />
{!disabled || model.processing ? (
<MiniButton
title='Отображение специальной клавиатуры'
icon={<IconControls size='1.25rem' className={showControls ? 'icon-primary' : ''} />}
onClick={() => setShowControls(prev => !prev)}
/>
) : null}
<MiniButton
title='Отображение списка конституент'
icon={showList ? <IconList size='1.25rem' className='icon-primary' /> : <IconListOff size='1.25rem' />}
onClick={onToggleList}
/>
<MiniButton
title='Дерево разбора выражения'
onClick={handleShowAST}
icon={<IconTree size='1.25rem' className='icon-primary' />}
/>
</Overlay>
<Overlay position='top-[-0.5rem] pl-[8rem] sm:pl-[4rem] right-1/2 translate-x-1/2 flex'> <Overlay position='top-[-0.5rem] pl-[8rem] sm:pl-[4rem] right-1/2 translate-x-1/2 flex'>
<StatusBar <StatusBar

View File

@ -0,0 +1,48 @@
import { IconControls, IconText, IconTextOff, IconTree } from '@/components/Icons';
import MiniButton from '@/components/ui/MiniButton';
import Overlay from '@/components/ui/Overlay';
import { useConceptOptions } from '@/context/OptionsContext';
import { useRSForm } from '@/context/RSFormContext';
interface ExpressionToolbarProps {
disabled?: boolean;
showControls: boolean;
toggleControls: () => void;
showAST: () => void;
}
function ExpressionToolbar({ disabled, showControls, toggleControls, showAST }: ExpressionToolbarProps) {
const model = useRSForm();
const { mathFont, setMathFont } = useConceptOptions();
function toggleFont() {
setMathFont(mathFont === 'math' ? 'math2' : 'math');
}
return (
<Overlay position='top-[-0.5rem] right-0 cc-icons'>
<MiniButton
title='Изменить шрифт'
onClick={toggleFont}
icon={
mathFont === 'math' ? <IconText size='1.25rem' className='icon-primary' /> : <IconTextOff size='1.25rem' />
}
/>
{!disabled || model.processing ? (
<MiniButton
title='Отображение специальной клавиатуры'
icon={<IconControls size='1.25rem' className={showControls ? 'icon-primary' : ''} />}
onClick={toggleControls}
/>
) : null}
<MiniButton
title='Дерево разбора выражения'
onClick={showAST}
icon={<IconTree size='1.25rem' className='icon-primary' />}
/>
</Overlay>
);
}
export default ExpressionToolbar;

View File

@ -1,3 +1,4 @@
import clsx from 'clsx';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import { TokenID } from '@/models/rslang'; import { TokenID } from '@/models/rslang';
@ -90,7 +91,13 @@ interface RSEditorControlsProps {
function RSEditorControls({ isOpen, disabled, onEdit }: RSEditorControlsProps) { function RSEditorControls({ isOpen, disabled, onEdit }: RSEditorControlsProps) {
return ( return (
<motion.div <motion.div
className='flex-wrap text-xs select-none sm:text-sm divide-solid' className={clsx(
'max-w-[38.5rem] sm:max-w-[40rem] sm:min-w-[40rem] md:max-w-fit mx-1 sm:mx-0',
'flex-wrap',
'divide-solid',
'text-xs md:text-sm',
'select-none'
)}
initial={false} initial={false}
animate={isOpen ? 'open' : 'closed'} animate={isOpen ? 'open' : 'closed'}
variants={animateRSControl} variants={animateRSControl}

View File

@ -26,8 +26,8 @@ function RSTokenButton({ token, disabled, onInsert }: RSTokenButtonProps) {
'font-math', 'font-math',
'cursor-pointer disabled:cursor-default', 'cursor-pointer disabled:cursor-default',
{ {
'w-[3.4rem] sm:w-[4.5rem]': label.length > 3, 'w-[3.7rem] md:w-[4.5rem]': label.length > 3,
'w-[1.7rem] sm:w-[2.25rem]': label.length <= 3 'w-[1.85rem] md:w-[2.25rem]': label.length <= 3
} }
)} )}
data-tooltip-id={globals.tooltip} data-tooltip-id={globals.tooltip}

View File

@ -30,7 +30,7 @@ function ViewConstituents({ expression, schema, activeCst, isBottom, onOpenEdit
const table = useMemo( const table = useMemo(
() => ( () => (
<ConstituentsTable <ConstituentsTable
maxHeight={isBottom ? '12rem' : calculateHeight('8.2rem')} maxHeight={isBottom ? calculateHeight('42rem') : calculateHeight('8.2rem')}
items={filteredData} items={filteredData}
activeCst={activeCst} activeCst={activeCst}
onOpenEdit={onOpenEdit} onOpenEdit={onOpenEdit}
@ -46,7 +46,7 @@ function ViewConstituents({ expression, schema, activeCst, isBottom, onOpenEdit
'border overflow-hidden', // prettier: split-lines 'border overflow-hidden', // prettier: split-lines
{ {
'mt-[2.2rem] rounded-l-md rounded-r-none': !isBottom, // prettier: split-lines 'mt-[2.2rem] rounded-l-md rounded-r-none': !isBottom, // prettier: split-lines
'mt-3 mx-6 rounded-md': isBottom 'mt-3 mx-6 rounded-md md:w-[45.8rem]': isBottom
} }
)} )}
initial={{ ...animateSideView.initial }} initial={{ ...animateSideView.initial }}