mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 13:00:39 +03:00
Improve tooltips
This commit is contained in:
parent
5b1fe5527f
commit
5e91eccd68
|
@ -1,16 +1,15 @@
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
|
|
||||||
|
import { CProps } from '@/components/props';
|
||||||
import { globalIDs } from '@/utils/constants';
|
import { globalIDs } from '@/utils/constants';
|
||||||
|
|
||||||
interface NavigationButtonProps {
|
interface NavigationButtonProps extends CProps.Titled {
|
||||||
text?: string;
|
text?: string;
|
||||||
icon: React.ReactNode;
|
icon: React.ReactNode;
|
||||||
title?: string;
|
|
||||||
titleHtml?: string;
|
|
||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
function NavigationButton({ icon, title, titleHtml, onClick, text }: NavigationButtonProps) {
|
function NavigationButton({ icon, title, titleHtml, hideTitle, onClick, text }: NavigationButtonProps) {
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
type='button'
|
type='button'
|
||||||
|
@ -18,6 +17,7 @@ function NavigationButton({ icon, title, titleHtml, onClick, text }: NavigationB
|
||||||
data-tooltip-id={!!title || !!titleHtml ? globalIDs.tooltip : undefined}
|
data-tooltip-id={!!title || !!titleHtml ? globalIDs.tooltip : undefined}
|
||||||
data-tooltip-html={titleHtml}
|
data-tooltip-html={titleHtml}
|
||||||
data-tooltip-content={title}
|
data-tooltip-content={title}
|
||||||
|
data-tooltip-hidden={hideTitle}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'mr-1 h-full', // prettier: split lines
|
'mr-1 h-full', // prettier: split lines
|
||||||
|
|
20
rsconcept/frontend/src/components/props.d.ts
vendored
20
rsconcept/frontend/src/components/props.d.ts
vendored
|
@ -2,8 +2,13 @@
|
||||||
import { HTMLMotionProps } from 'framer-motion';
|
import { HTMLMotionProps } from 'framer-motion';
|
||||||
|
|
||||||
export namespace CProps {
|
export namespace CProps {
|
||||||
export type Control = {
|
export type Titled = {
|
||||||
title?: string;
|
title?: string;
|
||||||
|
titleHtml?: string;
|
||||||
|
hideTitle?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Control = Titled & {
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
noBorder?: boolean;
|
noBorder?: boolean;
|
||||||
noOutline?: boolean;
|
noOutline?: boolean;
|
||||||
|
@ -23,7 +28,8 @@ export namespace CProps {
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Div = React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
|
export type Div = React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
|
||||||
export type Button = Omit<
|
export type Button = Titled &
|
||||||
|
Omit<
|
||||||
React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>,
|
React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>,
|
||||||
'children' | 'type'
|
'children' | 'type'
|
||||||
>;
|
>;
|
||||||
|
@ -31,12 +37,10 @@ export namespace CProps {
|
||||||
React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>,
|
React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>,
|
||||||
'children'
|
'children'
|
||||||
>;
|
>;
|
||||||
export type TextArea = React.DetailedHTMLProps<
|
export type TextArea = Titled &
|
||||||
React.TextareaHTMLAttributes<HTMLTextAreaElement>,
|
React.DetailedHTMLProps<React.TextareaHTMLAttributes<HTMLTextAreaElement>, HTMLTextAreaElement>;
|
||||||
HTMLTextAreaElement
|
export type Input = Titled & React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>;
|
||||||
>;
|
|
||||||
export type Input = React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>;
|
|
||||||
|
|
||||||
export type AnimatedButton = Omit<HTMLMotionProps<'button'>, 'type'>;
|
export type AnimatedButton = Titled & Omit<HTMLMotionProps<'button'>, 'type'>;
|
||||||
export type AnimatedDiv = HTMLMotionProps<'div'>;
|
export type AnimatedDiv = HTMLMotionProps<'div'>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,10 +7,8 @@ import { CProps } from '../props';
|
||||||
interface ButtonProps extends CProps.Control, CProps.Colors, CProps.Button {
|
interface ButtonProps extends CProps.Control, CProps.Colors, CProps.Button {
|
||||||
text?: string;
|
text?: string;
|
||||||
icon?: React.ReactNode;
|
icon?: React.ReactNode;
|
||||||
titleHtml?: string;
|
|
||||||
|
|
||||||
dense?: boolean;
|
dense?: boolean;
|
||||||
hideTitle?: boolean;
|
|
||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,10 +17,10 @@ function Button({
|
||||||
icon,
|
icon,
|
||||||
title,
|
title,
|
||||||
titleHtml,
|
titleHtml,
|
||||||
|
hideTitle,
|
||||||
loading,
|
loading,
|
||||||
dense,
|
dense,
|
||||||
disabled,
|
disabled,
|
||||||
hideTitle,
|
|
||||||
noBorder,
|
noBorder,
|
||||||
noOutline,
|
noOutline,
|
||||||
colors = 'clr-btn-default',
|
colors = 'clr-btn-default',
|
||||||
|
|
|
@ -8,14 +8,24 @@ import { CProps } from '../props';
|
||||||
|
|
||||||
export interface CheckboxProps extends Omit<CProps.Button, 'value' | 'onClick'> {
|
export interface CheckboxProps extends Omit<CProps.Button, 'value' | 'onClick'> {
|
||||||
label?: string;
|
label?: string;
|
||||||
titleHtml?: string;
|
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
|
|
||||||
value: boolean;
|
value: boolean;
|
||||||
setValue?: (newValue: boolean) => void;
|
setValue?: (newValue: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
function Checkbox({ id, disabled, label, title, titleHtml, className, value, setValue, ...restProps }: CheckboxProps) {
|
function Checkbox({
|
||||||
|
id,
|
||||||
|
disabled,
|
||||||
|
label,
|
||||||
|
title,
|
||||||
|
titleHtml,
|
||||||
|
hideTitle,
|
||||||
|
className,
|
||||||
|
value,
|
||||||
|
setValue,
|
||||||
|
...restProps
|
||||||
|
}: CheckboxProps) {
|
||||||
const cursor = useMemo(() => {
|
const cursor = useMemo(() => {
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
return 'cursor-not-allowed';
|
return 'cursor-not-allowed';
|
||||||
|
@ -50,6 +60,7 @@ function Checkbox({ id, disabled, label, title, titleHtml, className, value, set
|
||||||
data-tooltip-id={!!title || !!titleHtml ? globalIDs.tooltip : undefined}
|
data-tooltip-id={!!title || !!titleHtml ? globalIDs.tooltip : undefined}
|
||||||
data-tooltip-html={titleHtml}
|
data-tooltip-html={titleHtml}
|
||||||
data-tooltip-content={title}
|
data-tooltip-content={title}
|
||||||
|
data-tooltip-hidden={hideTitle}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -7,7 +7,6 @@ import { CheckboxCheckedIcon, CheckboxNullIcon } from '../Icons';
|
||||||
import { CheckboxProps } from './Checkbox';
|
import { CheckboxProps } from './Checkbox';
|
||||||
|
|
||||||
export interface CheckboxTristateProps extends Omit<CheckboxProps, 'value' | 'setValue'> {
|
export interface CheckboxTristateProps extends Omit<CheckboxProps, 'value' | 'setValue'> {
|
||||||
titleHtml?: string;
|
|
||||||
value: boolean | null;
|
value: boolean | null;
|
||||||
setValue?: (newValue: boolean | null) => void;
|
setValue?: (newValue: boolean | null) => void;
|
||||||
}
|
}
|
||||||
|
@ -18,6 +17,7 @@ function CheckboxTristate({
|
||||||
label,
|
label,
|
||||||
title,
|
title,
|
||||||
titleHtml,
|
titleHtml,
|
||||||
|
hideTitle,
|
||||||
className,
|
className,
|
||||||
value,
|
value,
|
||||||
setValue,
|
setValue,
|
||||||
|
@ -62,6 +62,7 @@ function CheckboxTristate({
|
||||||
data-tooltip-id={!!title || !!titleHtml ? globalIDs.tooltip : undefined}
|
data-tooltip-id={!!title || !!titleHtml ? globalIDs.tooltip : undefined}
|
||||||
data-tooltip-html={titleHtml}
|
data-tooltip-html={titleHtml}
|
||||||
data-tooltip-content={title}
|
data-tooltip-content={title}
|
||||||
|
data-tooltip-hidden={hideTitle}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -8,7 +8,6 @@ import { CProps } from '../props';
|
||||||
|
|
||||||
interface DropdownButtonProps extends CProps.AnimatedButton {
|
interface DropdownButtonProps extends CProps.AnimatedButton {
|
||||||
text?: string;
|
text?: string;
|
||||||
titleHtml?: string;
|
|
||||||
icon?: React.ReactNode;
|
icon?: React.ReactNode;
|
||||||
|
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
|
@ -20,6 +19,7 @@ function DropdownButton({
|
||||||
className,
|
className,
|
||||||
title,
|
title,
|
||||||
titleHtml,
|
titleHtml,
|
||||||
|
hideTitle,
|
||||||
onClick,
|
onClick,
|
||||||
children,
|
children,
|
||||||
...restProps
|
...restProps
|
||||||
|
@ -43,6 +43,7 @@ function DropdownButton({
|
||||||
data-tooltip-id={!!title || !!titleHtml ? globalIDs.tooltip : undefined}
|
data-tooltip-id={!!title || !!titleHtml ? globalIDs.tooltip : undefined}
|
||||||
data-tooltip-html={titleHtml}
|
data-tooltip-html={titleHtml}
|
||||||
data-tooltip-content={title}
|
data-tooltip-content={title}
|
||||||
|
data-tooltip-hidden={hideTitle}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
>
|
>
|
||||||
{children ? children : null}
|
{children ? children : null}
|
||||||
|
|
|
@ -6,18 +6,16 @@ import { CProps } from '../props';
|
||||||
|
|
||||||
interface MiniButtonProps extends CProps.Button {
|
interface MiniButtonProps extends CProps.Button {
|
||||||
icon: React.ReactNode;
|
icon: React.ReactNode;
|
||||||
titleHtml?: string;
|
|
||||||
noHover?: boolean;
|
noHover?: boolean;
|
||||||
hideTitle?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function MiniButton({
|
function MiniButton({
|
||||||
icon,
|
icon,
|
||||||
noHover,
|
noHover,
|
||||||
hideTitle,
|
|
||||||
tabIndex,
|
tabIndex,
|
||||||
title,
|
title,
|
||||||
titleHtml,
|
titleHtml,
|
||||||
|
hideTitle,
|
||||||
className,
|
className,
|
||||||
...restProps
|
...restProps
|
||||||
}: MiniButtonProps) {
|
}: MiniButtonProps) {
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { BiX } from 'react-icons/bi';
|
||||||
|
|
||||||
import useEscapeKey from '@/hooks/useEscapeKey';
|
import useEscapeKey from '@/hooks/useEscapeKey';
|
||||||
import { animateModal } from '@/styling/animations';
|
import { animateModal } from '@/styling/animations';
|
||||||
|
import { prepareTooltip } from '@/utils/labels';
|
||||||
|
|
||||||
import { CProps } from '../props';
|
import { CProps } from '../props';
|
||||||
import Button from './Button';
|
import Button from './Button';
|
||||||
|
@ -71,7 +72,11 @@ function Modal({
|
||||||
{...restProps}
|
{...restProps}
|
||||||
>
|
>
|
||||||
<Overlay position='right-[0.3rem] top-2'>
|
<Overlay position='right-[0.3rem] top-2'>
|
||||||
<MiniButton title='Закрыть диалоговое окно [ESC]' icon={<BiX size='1.25rem' />} onClick={handleCancel} />
|
<MiniButton
|
||||||
|
titleHtml={prepareTooltip('Закрыть диалоговое окно', 'ESC')}
|
||||||
|
icon={<BiX size='1.25rem' />}
|
||||||
|
onClick={handleCancel}
|
||||||
|
/>
|
||||||
</Overlay>
|
</Overlay>
|
||||||
|
|
||||||
{header ? <h1 className='px-12 py-2 select-none'>{header}</h1> : null}
|
{header ? <h1 className='px-12 py-2 select-none'>{header}</h1> : null}
|
||||||
|
|
|
@ -6,12 +6,10 @@ import { CProps } from '../props';
|
||||||
|
|
||||||
interface SelectorButtonProps extends CProps.Button {
|
interface SelectorButtonProps extends CProps.Button {
|
||||||
text?: string;
|
text?: string;
|
||||||
titleHtml?: string;
|
|
||||||
icon?: React.ReactNode;
|
icon?: React.ReactNode;
|
||||||
|
|
||||||
colors?: string;
|
colors?: string;
|
||||||
transparent?: boolean;
|
transparent?: boolean;
|
||||||
hideTitle?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function SelectorButton({
|
function SelectorButton({
|
||||||
|
|
|
@ -4,12 +4,13 @@ import { Tab as TabImpl } from 'react-tabs';
|
||||||
|
|
||||||
import { globalIDs } from '@/utils/constants';
|
import { globalIDs } from '@/utils/constants';
|
||||||
|
|
||||||
interface TabLabelProps extends Omit<TabPropsImpl, 'children'> {
|
import { CProps } from '../props';
|
||||||
|
|
||||||
|
interface TabLabelProps extends Omit<TabPropsImpl, 'children'>, CProps.Titled {
|
||||||
label?: string;
|
label?: string;
|
||||||
titleHtml?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function TabLabel({ label, title, titleHtml, className, ...otherProps }: TabLabelProps) {
|
function TabLabel({ label, title, titleHtml, hideTitle, className, ...otherProps }: TabLabelProps) {
|
||||||
return (
|
return (
|
||||||
<TabImpl
|
<TabImpl
|
||||||
className={clsx(
|
className={clsx(
|
||||||
|
@ -23,6 +24,7 @@ function TabLabel({ label, title, titleHtml, className, ...otherProps }: TabLabe
|
||||||
data-tooltip-id={!!title || !!titleHtml ? globalIDs.tooltip : undefined}
|
data-tooltip-id={!!title || !!titleHtml ? globalIDs.tooltip : undefined}
|
||||||
data-tooltip-html={titleHtml}
|
data-tooltip-html={titleHtml}
|
||||||
data-tooltip-content={title}
|
data-tooltip-content={title}
|
||||||
|
data-tooltip-hidden={hideTitle}
|
||||||
{...otherProps}
|
{...otherProps}
|
||||||
>
|
>
|
||||||
{label}
|
{label}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { FiSave } from 'react-icons/fi';
|
||||||
|
|
||||||
import MiniButton from '@/components/ui/MiniButton';
|
import MiniButton from '@/components/ui/MiniButton';
|
||||||
import Overlay from '@/components/ui/Overlay';
|
import Overlay from '@/components/ui/Overlay';
|
||||||
|
import { prepareTooltip } from '@/utils/labels';
|
||||||
|
|
||||||
interface ConstituentaToolbarProps {
|
interface ConstituentaToolbarProps {
|
||||||
isMutable: boolean;
|
isMutable: boolean;
|
||||||
|
@ -36,7 +37,7 @@ function ConstituentaToolbar({
|
||||||
return (
|
return (
|
||||||
<Overlay position='top-1 right-4 sm:right-1/2 sm:translate-x-1/2' className='flex'>
|
<Overlay position='top-1 right-4 sm:right-1/2 sm:translate-x-1/2' className='flex'>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
title='Сохранить изменения [Ctrl + S]'
|
titleHtml={prepareTooltip('Сохранить изменения', 'Ctrl + S')}
|
||||||
disabled={!canSave}
|
disabled={!canSave}
|
||||||
icon={<FiSave size='1.25rem' className='icon-primary' />}
|
icon={<FiSave size='1.25rem' className='icon-primary' />}
|
||||||
onClick={onSubmit}
|
onClick={onSubmit}
|
||||||
|
@ -54,7 +55,7 @@ function ConstituentaToolbar({
|
||||||
icon={<BiPlusCircle size={'1.25rem'} className='icon-green' />}
|
icon={<BiPlusCircle size={'1.25rem'} className='icon-green' />}
|
||||||
/>
|
/>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
title='Клонировать конституенту [Alt + V]'
|
titleHtml={prepareTooltip('Клонировать конституенту', 'Alt + V]')}
|
||||||
disabled={!isMutable || isModified}
|
disabled={!isMutable || isModified}
|
||||||
onClick={onClone}
|
onClick={onClone}
|
||||||
icon={<BiDuplicate size='1.25rem' className='icon-green' />}
|
icon={<BiDuplicate size='1.25rem' className='icon-green' />}
|
||||||
|
@ -66,13 +67,13 @@ function ConstituentaToolbar({
|
||||||
icon={<BiTrash size='1.25rem' className='icon-red' />}
|
icon={<BiTrash size='1.25rem' className='icon-red' />}
|
||||||
/>
|
/>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
title='Переместить вверх [Alt + вверх]'
|
titleHtml={prepareTooltip('Переместить вверх', 'Alt + вверх')}
|
||||||
icon={<BiUpvote size='1.25rem' className='icon-primary' />}
|
icon={<BiUpvote size='1.25rem' className='icon-primary' />}
|
||||||
disabled={!isMutable}
|
disabled={!isMutable}
|
||||||
onClick={onMoveUp}
|
onClick={onMoveUp}
|
||||||
/>
|
/>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
title='Переместить вниз [Alt + вниз]'
|
titleHtml={prepareTooltip('Переместить вниз', 'Alt + вниз')}
|
||||||
icon={<BiDownvote size='1.25rem' className='icon-primary' />}
|
icon={<BiDownvote size='1.25rem' className='icon-primary' />}
|
||||||
disabled={!isMutable}
|
disabled={!isMutable}
|
||||||
onClick={onMoveDown}
|
onClick={onMoveDown}
|
||||||
|
|
|
@ -1,23 +1,25 @@
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
|
|
||||||
|
import { CProps } from '@/components/props';
|
||||||
import { TokenID } from '@/models/rslang';
|
import { TokenID } from '@/models/rslang';
|
||||||
import { globalIDs } from '@/utils/constants';
|
import { globalIDs } from '@/utils/constants';
|
||||||
|
|
||||||
interface RSLocalButtonProps {
|
interface RSLocalButtonProps extends CProps.Titled {
|
||||||
text: string;
|
text: string;
|
||||||
title: string;
|
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
onInsert: (token: TokenID, key?: string) => void;
|
onInsert: (token: TokenID, key?: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
function RSLocalButton({ text, title, disabled, onInsert }: RSLocalButtonProps) {
|
function RSLocalButton({ text, title, titleHtml, hideTitle, disabled, onInsert }: RSLocalButtonProps) {
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
type='button'
|
type='button'
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
data-tooltip-id={title ? globalIDs.tooltip : undefined}
|
data-tooltip-id={!!title || !!titleHtml ? globalIDs.tooltip : undefined}
|
||||||
|
data-tooltip-html={titleHtml}
|
||||||
data-tooltip-content={title}
|
data-tooltip-content={title}
|
||||||
|
data-tooltip-hidden={hideTitle}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'w-[1.7rem] sm:w-[2rem] h-5 sm:h-6',
|
'w-[1.7rem] sm:w-[2rem] h-5 sm:h-6',
|
||||||
'cursor-pointer disabled:cursor-default',
|
'cursor-pointer disabled:cursor-default',
|
||||||
|
|
|
@ -31,7 +31,7 @@ function RSTokenButton({ token, disabled, onInsert }: RSTokenButtonProps) {
|
||||||
}
|
}
|
||||||
)}
|
)}
|
||||||
data-tooltip-id={globalIDs.tooltip}
|
data-tooltip-id={globalIDs.tooltip}
|
||||||
data-tooltip-content={describeToken(token)}
|
data-tooltip-html={describeToken(token)}
|
||||||
>
|
>
|
||||||
{label ? <span className='whitespace-nowrap'>{label}</span> : null}
|
{label ? <span className='whitespace-nowrap'>{label}</span> : null}
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -12,7 +12,7 @@ import { inferStatus } from '@/models/rsformAPI';
|
||||||
import { IExpressionParse, ParsingStatus } from '@/models/rslang';
|
import { IExpressionParse, ParsingStatus } from '@/models/rslang';
|
||||||
import { colorBgCstStatus } from '@/styling/color';
|
import { colorBgCstStatus } from '@/styling/color';
|
||||||
import { globalIDs } from '@/utils/constants';
|
import { globalIDs } from '@/utils/constants';
|
||||||
import { labelExpressionStatus } from '@/utils/labels';
|
import { labelExpressionStatus, prepareTooltip } from '@/utils/labels';
|
||||||
|
|
||||||
import StatusIcon from './StatusIcon';
|
import StatusIcon from './StatusIcon';
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ function StatusBar({ isModified, processing, constituenta, parseData, onAnalyze
|
||||||
)}
|
)}
|
||||||
style={{ backgroundColor: processing ? colors.bgDefault : colorBgCstStatus(status, colors) }}
|
style={{ backgroundColor: processing ? colors.bgDefault : colorBgCstStatus(status, colors) }}
|
||||||
data-tooltip-id={globalIDs.tooltip}
|
data-tooltip-id={globalIDs.tooltip}
|
||||||
data-tooltip-content='Проверить определение [Ctrl + Q]'
|
data-tooltip-html={prepareTooltip('Проверить определение', 'Ctrl + Q')}
|
||||||
onClick={onAnalyze}
|
onClick={onAnalyze}
|
||||||
>
|
>
|
||||||
<AnimatePresence mode='wait'>
|
<AnimatePresence mode='wait'>
|
||||||
|
|
|
@ -9,6 +9,7 @@ import HelpButton from '@/components/Help/HelpButton';
|
||||||
import MiniButton from '@/components/ui/MiniButton';
|
import MiniButton from '@/components/ui/MiniButton';
|
||||||
import Overlay from '@/components/ui/Overlay';
|
import Overlay from '@/components/ui/Overlay';
|
||||||
import { HelpTopic } from '@/models/miscellaneous';
|
import { HelpTopic } from '@/models/miscellaneous';
|
||||||
|
import { prepareTooltip } from '@/utils/labels';
|
||||||
|
|
||||||
import { useRSEdit } from '../RSEditContext';
|
import { useRSEdit } from '../RSEditContext';
|
||||||
|
|
||||||
|
@ -28,7 +29,7 @@ function RSFormToolbar({ modified, anonymous, subscribed, claimable, onSubmit, o
|
||||||
<Overlay position='top-1 right-1/2 translate-x-1/2' className='flex'>
|
<Overlay position='top-1 right-1/2 translate-x-1/2' className='flex'>
|
||||||
{controller.isContentEditable || controller.isProcessing ? (
|
{controller.isContentEditable || controller.isProcessing ? (
|
||||||
<MiniButton
|
<MiniButton
|
||||||
title='Сохранить изменения [Ctrl + S]'
|
titleHtml={prepareTooltip('Сохранить изменения', 'Ctrl + S')}
|
||||||
disabled={!canSave}
|
disabled={!canSave}
|
||||||
icon={<FiSave size='1.25rem' className='icon-primary' />}
|
icon={<FiSave size='1.25rem' className='icon-primary' />}
|
||||||
onClick={onSubmit}
|
onClick={onSubmit}
|
||||||
|
@ -46,7 +47,7 @@ function RSFormToolbar({ modified, anonymous, subscribed, claimable, onSubmit, o
|
||||||
/>
|
/>
|
||||||
{!anonymous ? (
|
{!anonymous ? (
|
||||||
<MiniButton
|
<MiniButton
|
||||||
title={`Отслеживание ${subscribed ? 'включено' : 'выключено'}`}
|
titleHtml={`Отслеживание <b>${subscribed ? 'включено' : 'выключено'}</b>`}
|
||||||
disabled={controller.isProcessing}
|
disabled={controller.isProcessing}
|
||||||
icon={
|
icon={
|
||||||
subscribed ? (
|
subscribed ? (
|
||||||
|
|
|
@ -13,7 +13,7 @@ import { HelpTopic } from '@/models/miscellaneous';
|
||||||
import { CstType } from '@/models/rsform';
|
import { CstType } from '@/models/rsform';
|
||||||
import { getCstTypePrefix } from '@/models/rsformAPI';
|
import { getCstTypePrefix } from '@/models/rsformAPI';
|
||||||
import { prefixes } from '@/utils/constants';
|
import { prefixes } from '@/utils/constants';
|
||||||
import { getCstTypeShortcut, labelCstType } from '@/utils/labels';
|
import { getCstTypeShortcut, labelCstType, prepareTooltip } from '@/utils/labels';
|
||||||
|
|
||||||
import { useRSEdit } from '../RSEditContext';
|
import { useRSEdit } from '../RSEditContext';
|
||||||
|
|
||||||
|
@ -29,25 +29,25 @@ function RSListToolbar({ selectedCount }: RSListToolbarProps) {
|
||||||
return (
|
return (
|
||||||
<Overlay position='top-1 right-1/2 translate-x-1/2' className='flex items-start'>
|
<Overlay position='top-1 right-1/2 translate-x-1/2' className='flex items-start'>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
title='Переместить вверх [Alt + вверх]'
|
titleHtml={prepareTooltip('Переместить вверх', 'Alt + вверх')}
|
||||||
icon={<BiUpvote size='1.25rem' className='icon-primary' />}
|
icon={<BiUpvote size='1.25rem' className='icon-primary' />}
|
||||||
disabled={!controller.isMutable || nothingSelected}
|
disabled={!controller.isMutable || nothingSelected}
|
||||||
onClick={controller.moveUp}
|
onClick={controller.moveUp}
|
||||||
/>
|
/>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
title='Переместить вниз [Alt + вниз]'
|
titleHtml={prepareTooltip('Переместить вниз', 'Alt + вниз')}
|
||||||
icon={<BiDownvote size='1.25rem' className='icon-primary' />}
|
icon={<BiDownvote size='1.25rem' className='icon-primary' />}
|
||||||
disabled={!controller.isMutable || nothingSelected}
|
disabled={!controller.isMutable || nothingSelected}
|
||||||
onClick={controller.moveDown}
|
onClick={controller.moveDown}
|
||||||
/>
|
/>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
title='Клонировать конституенту [Alt + V]'
|
titleHtml={prepareTooltip('Клонировать конституенту', 'Alt + V')}
|
||||||
icon={<BiDuplicate size='1.25rem' className='icon-green' />}
|
icon={<BiDuplicate size='1.25rem' className='icon-green' />}
|
||||||
disabled={!controller.isMutable || selectedCount !== 1}
|
disabled={!controller.isMutable || selectedCount !== 1}
|
||||||
onClick={controller.cloneCst}
|
onClick={controller.cloneCst}
|
||||||
/>
|
/>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
title='Добавить новую конституенту... [Alt + `]'
|
titleHtml={prepareTooltip('Добавить новую конституенту...', 'Alt + `')}
|
||||||
icon={<BiPlusCircle size='1.25rem' className='icon-green' />}
|
icon={<BiPlusCircle size='1.25rem' className='icon-green' />}
|
||||||
disabled={!controller.isMutable}
|
disabled={!controller.isMutable}
|
||||||
onClick={() => controller.createCst(undefined, false)}
|
onClick={() => controller.createCst(undefined, false)}
|
||||||
|
@ -66,13 +66,13 @@ function RSListToolbar({ selectedCount }: RSListToolbarProps) {
|
||||||
key={`${prefixes.csttype_list}${typeStr}`}
|
key={`${prefixes.csttype_list}${typeStr}`}
|
||||||
text={`${getCstTypePrefix(typeStr as CstType)}1 — ${labelCstType(typeStr as CstType)}`}
|
text={`${getCstTypePrefix(typeStr as CstType)}1 — ${labelCstType(typeStr as CstType)}`}
|
||||||
onClick={() => controller.createCst(typeStr as CstType, true)}
|
onClick={() => controller.createCst(typeStr as CstType, true)}
|
||||||
title={getCstTypeShortcut(typeStr as CstType)}
|
titleHtml={getCstTypeShortcut(typeStr as CstType)}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
</div>
|
</div>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
title='Удалить выбранные [Delete]'
|
titleHtml={prepareTooltip('Удалить выбранные', 'Delete')}
|
||||||
icon={<BiTrash size='1.25rem' className='icon-red' />}
|
icon={<BiTrash size='1.25rem' className='icon-red' />}
|
||||||
disabled={!controller.isMutable || nothingSelected}
|
disabled={!controller.isMutable || nothingSelected}
|
||||||
onClick={controller.deleteCst}
|
onClick={controller.deleteCst}
|
||||||
|
|
|
@ -38,7 +38,7 @@ function UserTabs() {
|
||||||
<div>
|
<div>
|
||||||
<Overlay position='top-0 right-0'>
|
<Overlay position='top-0 right-0'>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
title='Показать/Скрыть отслеживаемые схемы'
|
title='Отслеживаемые схемы'
|
||||||
icon={
|
icon={
|
||||||
showSubs ? (
|
showSubs ? (
|
||||||
<FiBell size='1.25rem' className='icon-primary' />
|
<FiBell size='1.25rem' className='icon-primary' />
|
||||||
|
|
|
@ -136,50 +136,50 @@ export function getCstTypeShortcut(type: CstType) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** <b></b><br/>
|
||||||
* Generates description for {@link TokenID}.
|
* Generates description for {@link TokenID}.
|
||||||
*/
|
*/
|
||||||
export function describeToken(id: TokenID): string {
|
export function describeToken(id: TokenID): string {
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case TokenID.BOOLEAN: return 'Булеан [Alt + E / Shift + B]';
|
case TokenID.BOOLEAN: return prepareTooltip('Булеан', 'Alt + E / Shift + B');
|
||||||
case TokenID.DECART: return 'Декартово произведение [Alt + Shift + E / Shift + 8]';
|
case TokenID.DECART: return prepareTooltip('Декартово произведение', 'Alt + Shift + E / Shift + 8');
|
||||||
case TokenID.PUNCTUATION_PL: return 'Скобки вокруг выражения [Alt + Shift + 9 ]';
|
case TokenID.PUNCTUATION_PL: return prepareTooltip('Скобки () вокруг выражения', 'Alt + Shift + 9');
|
||||||
case TokenID.PUNCTUATION_SL: return 'Скобки вокруг выражения [Alt + [ ]';
|
case TokenID.PUNCTUATION_SL: return prepareTooltip('Скобки [] вокруг выражения', 'Alt + [');
|
||||||
case TokenID.QUANTOR_UNIVERSAL: return 'Квантор всеобщности [`]';
|
case TokenID.QUANTOR_UNIVERSAL: return prepareTooltip('Квантор всеобщности', '`');
|
||||||
case TokenID.QUANTOR_EXISTS: return 'Квантор существования [Shift + `]';
|
case TokenID.QUANTOR_EXISTS: return prepareTooltip('Квантор существования', 'Shift + `');
|
||||||
case TokenID.LOGIC_NOT: return 'Отрицание [Alt + `]';
|
case TokenID.LOGIC_NOT: return prepareTooltip('Отрицание', 'Alt + `');
|
||||||
case TokenID.LOGIC_AND: return 'Конъюнкция [Alt + 3 ~ Shift + 7]';
|
case TokenID.LOGIC_AND: return prepareTooltip('Конъюнкция', 'Alt + 3 ~ Shift + 7');
|
||||||
case TokenID.LOGIC_OR: return 'Дизъюнкция [Alt + Shift + 3]';
|
case TokenID.LOGIC_OR: return prepareTooltip('Дизъюнкция', 'Alt + Shift + 3');
|
||||||
case TokenID.LOGIC_IMPLICATION: return 'Импликация [Alt + 4]';
|
case TokenID.LOGIC_IMPLICATION: return prepareTooltip('Импликация', 'Alt + 4');
|
||||||
case TokenID.LOGIC_EQUIVALENT: return 'Эквивалентность [Alt + Shift + 4]';
|
case TokenID.LOGIC_EQUIVALENT: return prepareTooltip('Эквивалентность', 'Alt + Shift + 4');
|
||||||
case TokenID.LIT_EMPTYSET: return 'Пустое множество [Alt + X]';
|
case TokenID.LIT_EMPTYSET: return prepareTooltip('Пустое множество', 'Alt + X');
|
||||||
case TokenID.LIT_WHOLE_NUMBERS: return 'Целые числа [Alt + Z]';
|
case TokenID.LIT_WHOLE_NUMBERS: return prepareTooltip('Целые числа', 'Alt + Z');
|
||||||
case TokenID.EQUAL: return 'Равенство';
|
case TokenID.EQUAL: return prepareTooltip('Равенство');
|
||||||
case TokenID.NOTEQUAL: return 'Неравенство [Alt + Shift + `]';
|
case TokenID.NOTEQUAL: return prepareTooltip('Неравенство', 'Alt + Shift + `');
|
||||||
case TokenID.GREATER_OR_EQ: return 'Больше или равно [Alt + Shift + 7]';
|
case TokenID.GREATER_OR_EQ: return prepareTooltip('Больше или равно', 'Alt + Shift + 7');
|
||||||
case TokenID.LESSER_OR_EQ: return 'Меньше или равно [Alt + Shift + 8]';
|
case TokenID.LESSER_OR_EQ: return prepareTooltip('Меньше или равно', 'Alt + Shift + 8');
|
||||||
case TokenID.SET_IN: return 'Быть элементом (принадлежит) [Alt + 1]';
|
case TokenID.SET_IN: return prepareTooltip('Быть элементом (принадлежит)', 'Alt + 1');
|
||||||
case TokenID.SET_NOT_IN: return 'Не принадлежит [Alt + Shift + 1]';
|
case TokenID.SET_NOT_IN: return prepareTooltip('Не принадлежит', 'Alt + Shift + 1');
|
||||||
case TokenID.SUBSET_OR_EQ: return 'Быть частью (нестрогое подмножество) [Alt + 2]';
|
case TokenID.SUBSET_OR_EQ: return prepareTooltip('Быть частью (нестрогое подмножество)', 'Alt + 2');
|
||||||
case TokenID.SUBSET: return 'Строгое подмножество [Alt + 7]';
|
case TokenID.SUBSET: return prepareTooltip('Строгое подмножество', 'Alt + 7');
|
||||||
case TokenID.NOT_SUBSET: return 'Не подмножество [Alt + Shift + 2]';
|
case TokenID.NOT_SUBSET: return prepareTooltip('Не подмножество', 'Alt + Shift + 2');
|
||||||
case TokenID.SET_INTERSECTION: return 'Пересечение [Alt + A]';
|
case TokenID.SET_INTERSECTION: return prepareTooltip('Пересечение', 'Alt + A');
|
||||||
case TokenID.SET_UNION: return 'Объединение [Alt + S]';
|
case TokenID.SET_UNION: return prepareTooltip('Объединение', 'Alt + S');
|
||||||
case TokenID.SET_MINUS: return 'Разность множеств [Alt + 5]';
|
case TokenID.SET_MINUS: return prepareTooltip('Разность множеств', 'Alt + 5');
|
||||||
case TokenID.SET_SYMMETRIC_MINUS: return 'Симметрическая разность [Alt + Shift + 5]';
|
case TokenID.SET_SYMMETRIC_MINUS: return prepareTooltip('Симметрическая разность', 'Alt + Shift + 5');
|
||||||
case TokenID.NT_DECLARATIVE_EXPR: return 'Декларативная форма определения терма [Alt + D]';
|
case TokenID.NT_DECLARATIVE_EXPR: return prepareTooltip('Декларативное определение', 'Alt + D');
|
||||||
case TokenID.NT_IMPERATIVE_EXPR: return 'Императивная форма определения терма [Alt + G]';
|
case TokenID.NT_IMPERATIVE_EXPR: return prepareTooltip('Императивное определение', 'Alt + G');
|
||||||
case TokenID.NT_RECURSIVE_FULL: return 'Рекурсивная (цикличная) форма определения терма [Alt + T]';
|
case TokenID.NT_RECURSIVE_FULL: return prepareTooltip('Рекурсивное определение (цикл)', 'Alt + T');
|
||||||
case TokenID.BIGPR: return 'Большая проекция [Alt + Q]';
|
case TokenID.BIGPR: return prepareTooltip('Большая проекция', 'Alt + Q');
|
||||||
case TokenID.SMALLPR: return 'Малая проекция [Alt + W]';
|
case TokenID.SMALLPR: return prepareTooltip('Малая проекция', 'Alt + W');
|
||||||
case TokenID.FILTER: return 'Фильтр [Alt + F]';
|
case TokenID.FILTER: return prepareTooltip('Фильтр', 'Alt + F');
|
||||||
case TokenID.REDUCE: return 'Множество-сумма [Alt + R]';
|
case TokenID.REDUCE: return prepareTooltip('Множество-сумма', 'Alt + R');
|
||||||
case TokenID.CARD: return 'Мощность [Alt + C]';
|
case TokenID.CARD: return prepareTooltip('Мощность', 'Alt + C');
|
||||||
case TokenID.BOOL: return 'Синглетон [Alt + B]';
|
case TokenID.BOOL: return prepareTooltip('Синглетон', 'Alt + B');
|
||||||
case TokenID.DEBOOL: return 'Десинглетон [Alt + V]';
|
case TokenID.DEBOOL: return prepareTooltip('Десинглетон', 'Alt + V');
|
||||||
case TokenID.PUNCTUATION_ASSIGN: return 'Присвоение (императивный синтаксис) [Alt + Shift + 6]';
|
case TokenID.PUNCTUATION_ASSIGN: return prepareTooltip('Присвоение', 'Alt + Shift + 6');
|
||||||
case TokenID.PUNCTUATION_ITERATE: return 'Перебор элементов множества (императивный синтаксис) [Alt + 6]';
|
case TokenID.PUNCTUATION_ITERATE: return prepareTooltip('Перебор элементов множества', 'Alt + 6');
|
||||||
}
|
}
|
||||||
return `no description: ${id}`;
|
return `no description: ${id}`;
|
||||||
}
|
}
|
||||||
|
@ -743,3 +743,10 @@ export function describeAccessMode(mode: UserAccessMode): string {
|
||||||
return 'Режим редактирования администратором';
|
return 'Режим редактирования администратором';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate HTML wrapper for control description including hotkey.
|
||||||
|
*/
|
||||||
|
export function prepareTooltip(text: string, hotkey?: string) {
|
||||||
|
return hotkey ? `<b>[${hotkey}]</b><br/>${text}` : text;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user