mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 13:00:39 +03:00
Refactor tooltips
This commit is contained in:
parent
8e84d570e3
commit
4d4d0a611d
|
@ -1,5 +1,7 @@
|
|||
import clsx from 'clsx';
|
||||
|
||||
import { globalIDs } from '@/utils/constants';
|
||||
|
||||
import { CProps } from '../props';
|
||||
|
||||
interface ButtonProps
|
||||
|
@ -12,8 +14,8 @@ extends CProps.Control, CProps.Colors, CProps.Button {
|
|||
}
|
||||
|
||||
function Button({
|
||||
text, icon, loading,
|
||||
dense, disabled, noBorder, noOutline,
|
||||
text, icon, title,
|
||||
loading, dense, disabled, noBorder, noOutline,
|
||||
colors = 'clr-btn-default',
|
||||
className,
|
||||
...restProps
|
||||
|
@ -36,6 +38,8 @@ function Button({
|
|||
className,
|
||||
colors
|
||||
)}
|
||||
data-tooltip-id={title ? (globalIDs.tooltip) : undefined}
|
||||
data-tooltip-content={title}
|
||||
{...restProps}
|
||||
>
|
||||
{icon ? icon : null}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import clsx from 'clsx';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { globalIDs } from '@/utils/constants';
|
||||
|
||||
import { CheckboxCheckedIcon } from '../Icons';
|
||||
import { CProps } from '../props';
|
||||
import Label from './Label';
|
||||
|
@ -15,7 +17,7 @@ extends Omit<CProps.Button, 'value' | 'onClick'> {
|
|||
}
|
||||
|
||||
function Checkbox({
|
||||
id, disabled, label,
|
||||
id, disabled, label, title,
|
||||
className, value, setValue, ...restProps
|
||||
}: CheckboxProps) {
|
||||
const cursor = useMemo(
|
||||
|
@ -48,6 +50,8 @@ function Checkbox({
|
|||
)}
|
||||
disabled={disabled}
|
||||
onClick={handleClick}
|
||||
data-tooltip-id={title ? (globalIDs.tooltip) : undefined}
|
||||
data-tooltip-content={title}
|
||||
{...restProps}
|
||||
>
|
||||
<div className={clsx(
|
||||
|
|
|
@ -2,12 +2,17 @@ import clsx from 'clsx';
|
|||
import type { TabProps } from 'react-tabs';
|
||||
import { Tab } from 'react-tabs';
|
||||
|
||||
import { globalIDs } from '@/utils/constants';
|
||||
|
||||
interface ConceptTabProps
|
||||
extends Omit<TabProps, 'children'> {
|
||||
label?: string
|
||||
}
|
||||
|
||||
function ConceptTab({ label, className, ...otherProps }: ConceptTabProps) {
|
||||
function ConceptTab({
|
||||
label, title, className,
|
||||
...otherProps
|
||||
}: ConceptTabProps) {
|
||||
return (
|
||||
<Tab
|
||||
className={clsx(
|
||||
|
@ -18,6 +23,8 @@ function ConceptTab({ label, className, ...otherProps }: ConceptTabProps) {
|
|||
'select-none hover:cursor-pointer',
|
||||
className
|
||||
)}
|
||||
data-tooltip-id={title ? (globalIDs.tooltip) : undefined}
|
||||
data-tooltip-content={title}
|
||||
{...otherProps}
|
||||
>
|
||||
{label}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
'use client';
|
||||
|
||||
import clsx from 'clsx';
|
||||
import { ReactNode } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
import { ITooltip, Tooltip } from 'react-tooltip';
|
||||
|
||||
|
@ -9,9 +10,11 @@ import { useConceptTheme } from '@/context/ThemeContext';
|
|||
interface ConceptTooltipProps
|
||||
extends Omit<ITooltip, 'variant'> {
|
||||
layer?: string
|
||||
text?: string
|
||||
}
|
||||
|
||||
function ConceptTooltip({
|
||||
text, children,
|
||||
layer='z-tooltip',
|
||||
place='bottom',
|
||||
className,
|
||||
|
@ -24,20 +27,25 @@ function ConceptTooltip({
|
|||
return null;
|
||||
}
|
||||
return createPortal(
|
||||
<Tooltip
|
||||
delayShow={500}
|
||||
(<Tooltip
|
||||
delayShow={1000}
|
||||
delayHide={100}
|
||||
opacity={0.97}
|
||||
className={clsx(
|
||||
'overflow-auto',
|
||||
'overflow-hidden',
|
||||
'border shadow-md',
|
||||
layer,
|
||||
className
|
||||
)}
|
||||
classNameArrow={layer}
|
||||
style={{...{ paddingTop: '2px', paddingBottom: '2px'}, ...style}}
|
||||
variant={(darkMode ? 'dark' : 'light')}
|
||||
place={place}
|
||||
{...restProps}
|
||||
/>, document.body);
|
||||
>
|
||||
{text}
|
||||
{children as ReactNode}
|
||||
</Tooltip>), document.body);
|
||||
}
|
||||
|
||||
export default ConceptTooltip;
|
|
@ -1,5 +1,7 @@
|
|||
import clsx from 'clsx';
|
||||
|
||||
import { globalIDs } from '@/utils/constants';
|
||||
|
||||
import { CProps } from '../props';
|
||||
|
||||
interface DropdownButtonProps
|
||||
|
@ -11,7 +13,9 @@ extends CProps.Button {
|
|||
}
|
||||
|
||||
function DropdownButton({
|
||||
text, icon, className, onClick,
|
||||
text, icon,
|
||||
className, title,
|
||||
onClick,
|
||||
children,
|
||||
...restProps
|
||||
}: DropdownButtonProps) {
|
||||
|
@ -29,6 +33,8 @@ function DropdownButton({
|
|||
},
|
||||
className
|
||||
)}
|
||||
data-tooltip-id={title ? (globalIDs.tooltip) : undefined}
|
||||
data-tooltip-content={title}
|
||||
{...restProps}
|
||||
>
|
||||
{children ? children : null}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import clsx from 'clsx';
|
||||
|
||||
import { globalIDs } from '@/utils/constants';
|
||||
|
||||
import { CProps } from '../props';
|
||||
|
||||
interface MiniButtonProps
|
||||
|
@ -10,7 +12,7 @@ extends CProps.Button {
|
|||
|
||||
function MiniButton({
|
||||
icon, noHover, tabIndex,
|
||||
className,
|
||||
title, className,
|
||||
...restProps
|
||||
}: MiniButtonProps) {
|
||||
return (
|
||||
|
@ -27,6 +29,8 @@ function MiniButton({
|
|||
},
|
||||
className
|
||||
)}
|
||||
data-tooltip-id={title ? (globalIDs.tooltip) : undefined}
|
||||
data-tooltip-content={title}
|
||||
{...restProps}
|
||||
>
|
||||
{icon}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import clsx from 'clsx';
|
||||
|
||||
import { globalIDs } from '@/utils/constants';
|
||||
|
||||
import { CProps } from '../props';
|
||||
|
||||
interface SelectorButtonProps
|
||||
|
@ -12,7 +14,7 @@ extends CProps.Button {
|
|||
}
|
||||
|
||||
function SelectorButton({
|
||||
text, icon,
|
||||
text, icon, title,
|
||||
colors = 'clr-btn-default',
|
||||
className,
|
||||
transparent,
|
||||
|
@ -20,6 +22,8 @@ function SelectorButton({
|
|||
}: SelectorButtonProps) {
|
||||
return (
|
||||
<button type='button'
|
||||
data-tooltip-id={title ? (globalIDs.tooltip) : undefined}
|
||||
data-tooltip-content={title}
|
||||
className={clsx(
|
||||
'px-1 flex flex-start items-center gap-1',
|
||||
'text-sm small-caps select-none',
|
||||
|
|
|
@ -16,7 +16,8 @@ function preventEnterCapture(event: React.KeyboardEvent<HTMLInputElement>) {
|
|||
}
|
||||
|
||||
function TextInput({
|
||||
id, label, dense, noBorder, noOutline, allowEnter, disabled,
|
||||
id, label,
|
||||
dense, noBorder, noOutline, allowEnter, disabled,
|
||||
className,
|
||||
colors = 'clr-input',
|
||||
onKeyDown,
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
import clsx from 'clsx';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { globalIDs } from '@/utils/constants';
|
||||
|
||||
import { CheckboxCheckedIcon, CheckboxNullIcon } from '../Icons';
|
||||
import { CheckboxProps } from './Checkbox';
|
||||
import Label from './Label';
|
||||
|
@ -13,7 +15,7 @@ extends Omit<CheckboxProps, 'value' | 'setValue'> {
|
|||
}
|
||||
|
||||
function Tristate({
|
||||
id, disabled, label,
|
||||
id, disabled, label, title,
|
||||
className,
|
||||
value, setValue,
|
||||
...restProps
|
||||
|
@ -53,6 +55,8 @@ function Tristate({
|
|||
)}
|
||||
disabled={disabled}
|
||||
onClick={handleClick}
|
||||
data-tooltip-id={title ? (globalIDs.tooltip) : undefined}
|
||||
data-tooltip-content={title}
|
||||
{...restProps}
|
||||
>
|
||||
<div className={clsx(
|
||||
|
|
|
@ -28,7 +28,7 @@ function HelpTermGraph() {
|
|||
|
||||
<Divider margins='mt-2' />
|
||||
|
||||
<InfoCstClass title='Классы конституент' />
|
||||
<InfoCstClass header='Классы конституент' />
|
||||
</div>
|
||||
</div>);
|
||||
}
|
||||
|
|
|
@ -42,19 +42,19 @@ function Navigation () {
|
|||
<div className='flex'>
|
||||
<NavigationButton
|
||||
text='Новая схема'
|
||||
description='Создать новую схему'
|
||||
title='Создать новую схему'
|
||||
icon={<FaSquarePlus size='1.5rem' />}
|
||||
onClick={navigateCreateNew}
|
||||
/>
|
||||
<NavigationButton
|
||||
text='Библиотека'
|
||||
description='Библиотека концептуальных схем'
|
||||
title='Список схем'
|
||||
icon={<IoLibrary size='1.5rem' />}
|
||||
onClick={navigateLibrary}
|
||||
/>
|
||||
<NavigationButton
|
||||
text='Справка'
|
||||
description='Справочные материалы и обучение'
|
||||
title='Справочные материалы'
|
||||
icon={<EducationIcon />}
|
||||
onClick={navigateHelp}
|
||||
/>
|
||||
|
|
|
@ -1,17 +1,19 @@
|
|||
import clsx from 'clsx';
|
||||
|
||||
import { globalIDs } from '@/utils/constants';
|
||||
|
||||
interface NavigationButtonProps {
|
||||
id?: string
|
||||
text?: string
|
||||
icon: React.ReactNode
|
||||
description?: string
|
||||
title?: string
|
||||
onClick?: () => void
|
||||
}
|
||||
|
||||
function NavigationButton({ id, icon, description, onClick, text }: NavigationButtonProps) {
|
||||
function NavigationButton({ icon, title, onClick, text }: NavigationButtonProps) {
|
||||
return (
|
||||
<button id={id} type='button' tabIndex={-1}
|
||||
title={description}
|
||||
<button type='button' tabIndex={-1}
|
||||
data-tooltip-id={title ? (globalIDs.tooltip) : undefined}
|
||||
data-tooltip-content={title}
|
||||
onClick={onClick}
|
||||
className={clsx(
|
||||
'mr-1 h-full',
|
||||
|
|
|
@ -18,13 +18,12 @@ function UserMenu() {
|
|||
<div ref={menu.ref} className='h-full'>
|
||||
{!user ?
|
||||
<NavigationButton
|
||||
description='Перейти на страницу логина'
|
||||
icon={<InDoorIcon />}
|
||||
title='Перейти на страницу логина'
|
||||
icon={<InDoorIcon size='1.5rem' className='clr-text-primary' />}
|
||||
onClick={navigateLogin}
|
||||
/> : null}
|
||||
{user ?
|
||||
<NavigationButton
|
||||
description={`Пользователь ${user?.username}`}
|
||||
icon={<FaCircleUser size='1.5rem' />}
|
||||
onClick={menu.toggle}
|
||||
/> : null}
|
||||
|
|
|
@ -7,15 +7,15 @@ import { prefixes } from '@/utils/constants';
|
|||
import { describeCstClass, labelCstClass } from '@/utils/labels';
|
||||
|
||||
interface InfoCstClassProps {
|
||||
title?: string
|
||||
header?: string
|
||||
}
|
||||
|
||||
function InfoCstClass({ title }: InfoCstClassProps) {
|
||||
function InfoCstClass({ header }: InfoCstClassProps) {
|
||||
const { colors } = useConceptTheme();
|
||||
|
||||
return (
|
||||
<div className='flex flex-col gap-1 mb-2'>
|
||||
{title ? <h1>{title}</h1> : null}
|
||||
{header ? <h1>{header}</h1> : null}
|
||||
{Object.values(CstClass).map(
|
||||
(cclass, index) => {
|
||||
return (
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
'use client';
|
||||
|
||||
import clsx from 'clsx';
|
||||
import { createContext, useContext, useLayoutEffect, useMemo, useState } from 'react';
|
||||
|
||||
import ConceptTooltip from '@/components/Common/ConceptTooltip';
|
||||
import useLocalStorage from '@/hooks/useLocalStorage';
|
||||
import { darkT, IColorTheme, lightT } from '@/utils/color';
|
||||
import { globalIDs } from '@/utils/constants';
|
||||
|
||||
interface IThemeContext {
|
||||
viewportHeight: string
|
||||
|
@ -85,6 +88,17 @@ export const ThemeState = ({ children }: ThemeStateProps) => {
|
|||
setNoFooter, setShowScroll,
|
||||
viewportHeight, mainHeight
|
||||
}}>
|
||||
<>
|
||||
<ConceptTooltip float
|
||||
id={`${globalIDs.tooltip}`}
|
||||
layer='z-topmost'
|
||||
place='right-start'
|
||||
className={clsx(
|
||||
'mt-3 translate-y-1/2',
|
||||
'max-w-[20rem]'
|
||||
)}
|
||||
/>
|
||||
{children}
|
||||
</>
|
||||
</ThemeContext.Provider>);
|
||||
}
|
|
@ -83,6 +83,9 @@
|
|||
.z-modal-tooltip {
|
||||
z-index: 90;
|
||||
}
|
||||
.z-topmost {
|
||||
z-index: 99;
|
||||
}
|
||||
|
||||
|
||||
:root {
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
import clsx from 'clsx';
|
||||
|
||||
import { TokenID } from '@/models/rslang';
|
||||
import { globalIDs } from '@/utils/constants';
|
||||
|
||||
interface RSLocalButtonProps {
|
||||
text: string
|
||||
|
@ -11,8 +14,14 @@ function RSLocalButton({ text, title, disabled, onInsert }: RSLocalButtonProps)
|
|||
return (
|
||||
<button type='button' tabIndex={-1}
|
||||
disabled={disabled}
|
||||
title={title}
|
||||
className='w-[2rem] h-6 cursor-pointer disabled:cursor-default rounded-none clr-hover clr-btn-clear'
|
||||
data-tooltip-id={title ? globalIDs.tooltip: undefined}
|
||||
data-tooltip-content={title}
|
||||
className={clsx(
|
||||
'w-[2rem] h-6',
|
||||
'cursor-pointer disabled:cursor-default',
|
||||
'rounded-none',
|
||||
'clr-hover clr-btn-clear'
|
||||
)}
|
||||
onClick={() => onInsert(TokenID.ID_LOCAL, text)}
|
||||
>
|
||||
{text}
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
import clsx from 'clsx';
|
||||
|
||||
import { TokenID } from '@/models/rslang';
|
||||
import { globalIDs } from '@/utils/constants';
|
||||
import { describeToken, labelToken } from '@/utils/labels';
|
||||
|
||||
interface RSTokenButtonProps {
|
||||
|
@ -9,13 +12,23 @@ interface RSTokenButtonProps {
|
|||
|
||||
function RSTokenButton({ token, disabled, onInsert }: RSTokenButtonProps) {
|
||||
const label = labelToken(token);
|
||||
const width = label.length > 3 ? 'w-[4.5rem]' : 'w-[2.25rem]';
|
||||
return (
|
||||
<button type='button' tabIndex={-1}
|
||||
disabled={disabled}
|
||||
onClick={() => onInsert(token)}
|
||||
title={describeToken(token)}
|
||||
className={`px-1 cursor-pointer disabled:cursor-default h-6 ${width} outline-none clr-hover clr-btn-clear`}
|
||||
className={clsx(
|
||||
'h-6',
|
||||
'px-1',
|
||||
'outline-none',
|
||||
'clr-hover clr-btn-clear',
|
||||
'cursor-pointer disabled:cursor-default',
|
||||
{
|
||||
'w-[4.5rem]': label.length > 3,
|
||||
'w-[2.25rem]': label.length <= 3
|
||||
}
|
||||
)}
|
||||
data-tooltip-id={globalIDs.tooltip}
|
||||
data-tooltip-content={describeToken(token)}
|
||||
>
|
||||
{label ? <span className='whitespace-nowrap'>{label}</span> : null}
|
||||
</button>);
|
||||
|
|
|
@ -10,6 +10,7 @@ import { type IConstituenta } from '@/models/rsform';
|
|||
import { inferStatus } from '@/models/rsformAPI';
|
||||
import { IExpressionParse, ParsingStatus } from '@/models/rslang';
|
||||
import { colorbgCstStatus } from '@/utils/color';
|
||||
import { globalIDs } from '@/utils/constants';
|
||||
import { labelExpressionStatus } from '@/utils/labels';
|
||||
|
||||
import StatusIcon from './StatusIcon';
|
||||
|
@ -37,7 +38,6 @@ function StatusBar({ isModified, processing, constituenta, parseData, onAnalyze
|
|||
|
||||
return (
|
||||
<div
|
||||
title='Проверить определение [Ctrl + Q]'
|
||||
className={clsx(
|
||||
'w-[10rem] h-[1.75rem]',
|
||||
'px-2 flex items-center justify-center gap-2',
|
||||
|
@ -47,6 +47,8 @@ function StatusBar({ isModified, processing, constituenta, parseData, onAnalyze
|
|||
'duration-500 transition-colors'
|
||||
)}
|
||||
style={{backgroundColor: processing ? colors.bgDefault : colorbgCstStatus(status, colors)}}
|
||||
data-tooltip-id={globalIDs.tooltip}
|
||||
data-tooltip-content='Проверить определение [Ctrl + Q]'
|
||||
onClick={onAnalyze}
|
||||
>
|
||||
{processing ?
|
||||
|
|
|
@ -52,7 +52,7 @@ function RSFormToolbar({
|
|||
onClick={onDownload}
|
||||
/>
|
||||
<MiniButton
|
||||
title={'отслеживание: ' + (isSubscribed ? '[включено]' : '[выключено]')}
|
||||
title={'Отслеживание ' + (isSubscribed ? 'включено' : 'выключено')}
|
||||
disabled={anonymous || processing}
|
||||
icon={isSubscribed
|
||||
? <FiBell size='1.25rem' className='clr-text-primary' />
|
||||
|
@ -62,7 +62,7 @@ function RSFormToolbar({
|
|||
onClick={onToggleSubscribe}
|
||||
/>
|
||||
<MiniButton
|
||||
title={claimable ? 'Стать владельцем' : 'Невозможно стать владельцем' }
|
||||
title='Стать владельцем'
|
||||
icon={<LuCrown size='1.25rem' className={!claimable || anonymous ? '' : 'clr-text-success'}/>}
|
||||
disabled={!claimable || anonymous || processing}
|
||||
onClick={onClaim}
|
||||
|
|
|
@ -419,10 +419,7 @@ function RSTabs() {
|
|||
/>
|
||||
<ConceptTab
|
||||
label='Содержание'
|
||||
title={[
|
||||
`Всего конституент: ${schema.stats?.count_all ?? 0}`,
|
||||
`Количество ошибок: ${schema.stats?.count_errors ?? 0}`
|
||||
].join('\n')}
|
||||
title={`Конституент: ${schema.stats?.count_all ?? 0} | Ошибок: ${schema.stats?.count_errors ?? 0}`}
|
||||
/>
|
||||
<ConceptTab label='Редактор' />
|
||||
<ConceptTab label='Граф термов' />
|
||||
|
|
|
@ -172,7 +172,7 @@ function RSTabsMenu({
|
|||
|
||||
<div ref={accessMenu.ref}>
|
||||
<Button dense noBorder tabIndex={-1}
|
||||
title={`режим ${labelAccessMode(mode)}`}
|
||||
title={`Режим ${labelAccessMode(mode)}`}
|
||||
className='h-full pr-2'
|
||||
style={{outlineColor: 'transparent'}}
|
||||
icon={
|
||||
|
|
|
@ -189,9 +189,9 @@ export function domTooltipEntityReference(ref: IEntityReference, cst: IConstitue
|
|||
'select-none cursor-auto'
|
||||
);
|
||||
|
||||
const title = document.createElement('p');
|
||||
title.innerHTML = '<b>Ссылка на конституенту</b>';
|
||||
dom.appendChild(title);
|
||||
const header = document.createElement('p');
|
||||
header.innerHTML = '<b>Ссылка на конституенту</b>';
|
||||
dom.appendChild(header);
|
||||
|
||||
const term = document.createElement('p');
|
||||
term.innerHTML = `<b>${ref.entity}:</b> ${describeConstituentaTerm(cst)}`;
|
||||
|
@ -237,9 +237,9 @@ export function domTooltipSyntacticReference(ref: ISyntacticReference, masterRef
|
|||
'select-none cursor-auto'
|
||||
);
|
||||
|
||||
const title = document.createElement('p');
|
||||
title.innerHTML = '<b>Связывание слов</b>';
|
||||
dom.appendChild(title);
|
||||
const header = document.createElement('p');
|
||||
header.innerHTML = '<b>Связывание слов</b>';
|
||||
dom.appendChild(header);
|
||||
|
||||
const offset = document.createElement('p');
|
||||
offset.innerHTML = `<b>Смещение:</b> ${ref.offset}`;
|
||||
|
|
|
@ -83,6 +83,7 @@ export const urls = {
|
|||
* Global unique IDs.
|
||||
*/
|
||||
export const globalIDs = {
|
||||
tooltip: 'global-tooltip',
|
||||
password_tooltip: 'password-tooltip',
|
||||
main_scroll: 'main-scroll',
|
||||
library_item_editor: 'library-item-editor',
|
||||
|
|
Loading…
Reference in New Issue
Block a user