mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-08-14 12:50:37 +03:00
F: Improve tooltips for Mac
This commit is contained in:
parent
96b05d1fe6
commit
b95952a5e5
|
@ -1,5 +1,6 @@
|
|||
// Search new icons at https://reactsvgicons.com/
|
||||
// Note: save this file using Ctrl + K, Ctrl + Shift + S to disable autoformat
|
||||
// Note: For Cursor hotkeys are Ctrl + M, Ctrl + Shift + S
|
||||
|
||||
/* eslint-disable simple-import-sort/exports */
|
||||
// ==== General actions =======
|
||||
|
|
|
@ -8,6 +8,7 @@ import {
|
|||
IconPin,
|
||||
IconUser2
|
||||
} from '@/components/icons';
|
||||
import { isMac } from '@/utils/utils';
|
||||
|
||||
import { Subtopics } from '../components/subtopics';
|
||||
import { HelpTopic } from '../models/help-topic';
|
||||
|
@ -33,7 +34,7 @@ export function HelpInterface() {
|
|||
<h2>Навигация и настройки</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<kbd>Ctrl + клик</kbd> на объект навигации откроет новую вкладку
|
||||
<kbd>{isMac() ? 'Cmd + клик' : 'Ctrl + клик'}</kbd> на объект навигации откроет новую вкладку
|
||||
</li>
|
||||
<li>
|
||||
<IconPin size='1.25rem' className='inline-icon' /> навигационную панель можно скрыть с помощью кнопки в правом
|
||||
|
|
|
@ -15,6 +15,7 @@ import {
|
|||
IconSubfolders,
|
||||
IconUserSearch
|
||||
} from '@/components/icons';
|
||||
import { isMac } from '@/utils/utils';
|
||||
|
||||
import { LinkTopic } from '../../components/link-topic';
|
||||
import { HelpTopic } from '../../models/help-topic';
|
||||
|
@ -38,7 +39,7 @@ export function HelpLibrary() {
|
|||
<kbd>клик</kbd> по строке - переход к редактированию схемы
|
||||
</li>
|
||||
<li>
|
||||
<kbd>Ctrl + клик</kbd> по строке откроет схему в новой вкладке
|
||||
<kbd>{isMac() ? 'Cmd + клик' : 'Ctrl + клик'}</kbd> по строке откроет схему в новой вкладке
|
||||
</li>
|
||||
<li>Фильтры атрибутов три позиции: да/нет/не применять</li>
|
||||
<li>
|
||||
|
@ -74,7 +75,11 @@ export function HelpLibrary() {
|
|||
<kbd>клик</kbd> по папке отображает справа схемы в ней
|
||||
</li>
|
||||
<li>
|
||||
<kbd>Ctrl + клик по папке копирует путь в буфер обмена</kbd>
|
||||
<kbd>
|
||||
{isMac()
|
||||
? 'Cmd + клик по папке копирует путь в буфер обмена'
|
||||
: 'Ctrl + клик по папке копирует путь в буфер обмена'}
|
||||
</kbd>
|
||||
</li>
|
||||
<li>
|
||||
<kbd>клик</kbd> по иконке сворачивает/разворачивает вложенные
|
||||
|
|
|
@ -8,6 +8,7 @@ import {
|
|||
IconPublic,
|
||||
IconSave
|
||||
} from '@/components/icons';
|
||||
import { isMac } from '@/utils/utils';
|
||||
|
||||
import { LinkTopic } from '../../components/link-topic';
|
||||
import { HelpTopic } from '../../models/help-topic';
|
||||
|
@ -34,7 +35,7 @@ export function HelpRSCard() {
|
|||
<IconOSS className='inline-icon' /> переход к связанной <LinkTopic text='ОСС' topic={HelpTopic.CC_OSS} />
|
||||
</li>
|
||||
<li>
|
||||
<IconSave className='inline-icon' /> сохранить изменения: <kbd>Ctrl + S</kbd>
|
||||
<IconSave className='inline-icon' /> сохранить изменения: <kbd>{isMac() ? 'Cmd + S' : 'Ctrl + S'}</kbd>
|
||||
</li>
|
||||
<li>
|
||||
<IconEditor className='inline-icon' /> Редактор обладает правом редактирования
|
||||
|
|
|
@ -18,6 +18,7 @@ import {
|
|||
IconTree,
|
||||
IconTypeGraph
|
||||
} from '@/components/icons';
|
||||
import { isMac } from '@/utils/utils';
|
||||
|
||||
import { LinkTopic } from '../../components/link-topic';
|
||||
import { HelpTopic } from '../../models/help-topic';
|
||||
|
@ -40,7 +41,7 @@ export function HelpRSEditor() {
|
|||
<IconLeftOpen className='inline-icon' /> список конституент
|
||||
</li>
|
||||
<li>
|
||||
<IconSave className='inline-icon' /> сохранить: <kbd>Ctrl + S</kbd>
|
||||
<IconSave className='inline-icon' /> сохранить: <kbd>{isMac() ? 'Cmd + S' : 'Ctrl + S'}</kbd>
|
||||
</li>
|
||||
<li>
|
||||
<IconReset className='inline-icon' /> сбросить изменения
|
||||
|
@ -104,7 +105,7 @@ export function HelpRSEditor() {
|
|||
<LinkTopic text='дерева разбора' topic={HelpTopic.UI_FORMULA_TREE} />
|
||||
</li>
|
||||
<li>
|
||||
<kbd>Ctrl + Пробел</kbd> вставка незанятого имени / замена проекции
|
||||
<kbd>{isMac() ? 'Cmd + Пробел' : 'Ctrl + Пробел'}</kbd> вставка незанятого имени / замена проекции
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
@ -116,7 +117,7 @@ export function HelpRSEditor() {
|
|||
<LinkTopic text='Термина' topic={HelpTopic.CC_CONSTITUENTA} />
|
||||
</li>
|
||||
<li>
|
||||
<kbd>Ctrl + Пробел</kbd> открывает редактирование отсылок
|
||||
<kbd>{isMac() ? 'Cmd + Пробел' : 'Ctrl + Пробел'}</kbd> открывает редактирование отсылок
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
|
@ -12,7 +12,7 @@ import { cn } from '@/components/utils';
|
|||
import { useModificationStore } from '@/stores/modification';
|
||||
import { usePreferencesStore } from '@/stores/preferences';
|
||||
import { tooltipText } from '@/utils/labels';
|
||||
import { prepareTooltip, sharePage } from '@/utils/utils';
|
||||
import { isMac, prepareTooltip, sharePage } from '@/utils/utils';
|
||||
|
||||
import { AccessPolicy, type ILibraryItem, LibraryItemType } from '../backend/types';
|
||||
import { useMutatingLibrary } from '../backend/use-mutating-library';
|
||||
|
@ -71,7 +71,7 @@ export function ToolbarItemCard({
|
|||
{ossSelector}
|
||||
{isMutable || isModified ? (
|
||||
<MiniButton
|
||||
titleHtml={prepareTooltip('Сохранить изменения', 'Ctrl + S')}
|
||||
titleHtml={prepareTooltip('Сохранить изменения', isMac() ? 'Cmd + S' : 'Ctrl + S')}
|
||||
aria-label='Сохранить изменения'
|
||||
icon={<IconSave size='1.25rem' className='icon-primary' />}
|
||||
onClick={onSubmit}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
'use client';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
import { urls, useConceptNavigation } from '@/app';
|
||||
import { useLibrary } from '@/features/library/backend/use-library';
|
||||
|
||||
import { DropdownButton } from '@/components/dropdown';
|
||||
|
@ -33,7 +32,6 @@ interface MenuOperationProps {
|
|||
}
|
||||
|
||||
export function MenuOperation({ operation, onHide }: MenuOperationProps) {
|
||||
const router = useConceptNavigation();
|
||||
const { items: libraryItems } = useLibrary();
|
||||
const { schema, navigateOperationSchema, isMutable, canDeleteOperation } = useOssEdit();
|
||||
const isProcessing = useMutatingOss();
|
||||
|
@ -134,7 +132,7 @@ export function MenuOperation({ operation, onHide }: MenuOperationProps) {
|
|||
void inputCreate({
|
||||
itemID: schema.id,
|
||||
data: { target: operation.id, layout: getLayout() }
|
||||
}).then(new_schema => router.push({ path: urls.schema(new_schema.id), force: true }));
|
||||
});
|
||||
}
|
||||
|
||||
function handleRelocateConstituents() {
|
||||
|
|
|
@ -163,14 +163,16 @@ export function OssFlow() {
|
|||
handleSavePositions();
|
||||
return;
|
||||
}
|
||||
if ((event.ctrlKey || event.metaKey) && event.code === 'KeyQ') {
|
||||
if (event.altKey && event.code === 'Key1') {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
if (event.shiftKey) {
|
||||
handleCreateBlock();
|
||||
} else {
|
||||
handleCreateOperation();
|
||||
}
|
||||
handleCreateBlock();
|
||||
return;
|
||||
}
|
||||
if (event.altKey && event.code === 'Key2') {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
handleCreateOperation();
|
||||
return;
|
||||
}
|
||||
if (event.key === 'Delete') {
|
||||
|
@ -200,8 +202,10 @@ export function OssFlow() {
|
|||
|
||||
<ToolbarOssGraph
|
||||
className='absolute z-pop top-8 right-1/2 translate-x-1/2'
|
||||
onCreateOperation={handleCreateOperation}
|
||||
onCreateBlock={handleCreateBlock}
|
||||
onCreateSchema={handleCreateOperation}
|
||||
onImportSchema={handleCreateOperation}
|
||||
onCreateSynthesis={handleCreateOperation}
|
||||
onDelete={handleDeleteSelected}
|
||||
onResetPositions={resetGraph}
|
||||
openContextMenu={openContextMenu}
|
||||
|
|
|
@ -2,16 +2,21 @@
|
|||
|
||||
import React from 'react';
|
||||
|
||||
import { useAuthSuspense } from '@/features/auth/backend/use-auth';
|
||||
import { HelpTopic } from '@/features/help';
|
||||
import { BadgeHelp } from '@/features/help/components/badge-help';
|
||||
import { IconShowSidebar } from '@/features/library/components/icon-show-sidebar';
|
||||
import { type OssNode } from '@/features/oss/models/oss-layout';
|
||||
|
||||
import { MiniButton } from '@/components/control';
|
||||
import { Dropdown, DropdownButton, useDropdown } from '@/components/dropdown';
|
||||
import {
|
||||
IconClustering,
|
||||
IconConceptBlock,
|
||||
IconDestroy,
|
||||
IconDownload,
|
||||
IconEdit2,
|
||||
IconFilter,
|
||||
IconFitImage,
|
||||
IconNewItem,
|
||||
IconReset,
|
||||
|
@ -22,7 +27,7 @@ import { type Styling } from '@/components/props';
|
|||
import { cn } from '@/components/utils';
|
||||
import { useDialogsStore } from '@/stores/dialogs';
|
||||
import { usePreferencesStore } from '@/stores/preferences';
|
||||
import { isIOS, prepareTooltip } from '@/utils/utils';
|
||||
import { isIOS, isMac, notImplemented, prepareTooltip } from '@/utils/utils';
|
||||
|
||||
import { useMutatingOss } from '../../../backend/use-mutating-oss';
|
||||
import { useUpdateLayout } from '../../../backend/use-update-layout';
|
||||
|
@ -33,8 +38,10 @@ import { useOssFlow } from './oss-flow-context';
|
|||
import { useGetLayout } from './use-get-layout';
|
||||
|
||||
interface ToolbarOssGraphProps extends Styling {
|
||||
onCreateOperation: () => void;
|
||||
onCreateBlock: () => void;
|
||||
onCreateSchema: () => void;
|
||||
onImportSchema: () => void;
|
||||
onCreateSynthesis: () => void;
|
||||
onDelete: () => void;
|
||||
onResetPositions: () => void;
|
||||
|
||||
|
@ -44,8 +51,10 @@ interface ToolbarOssGraphProps extends Styling {
|
|||
}
|
||||
|
||||
export function ToolbarOssGraph({
|
||||
onCreateOperation,
|
||||
onCreateBlock,
|
||||
onCreateSchema,
|
||||
onImportSchema,
|
||||
onCreateSynthesis,
|
||||
onDelete,
|
||||
onResetPositions,
|
||||
|
||||
|
@ -58,18 +67,25 @@ export function ToolbarOssGraph({
|
|||
const { schema, selectedItems, isMutable, canDeleteOperation: canDelete } = useOssEdit();
|
||||
const isProcessing = useMutatingOss();
|
||||
const { resetView, nodes } = useOssFlow();
|
||||
const selectedOperation =
|
||||
selectedItems.length === 1 && selectedItems[0].nodeType === NodeType.OPERATION ? selectedItems[0] : null;
|
||||
const selectedBlock =
|
||||
selectedItems.length === 1 && selectedItems[0].nodeType === NodeType.BLOCK ? selectedItems[0] : null;
|
||||
const getLayout = useGetLayout();
|
||||
|
||||
const { updateLayout } = useUpdateLayout();
|
||||
const { user } = useAuthSuspense();
|
||||
const menu = useDropdown();
|
||||
|
||||
const showOptions = useDialogsStore(state => state.showOssOptions);
|
||||
const showSidePanel = usePreferencesStore(state => state.showOssSidePanel);
|
||||
const toggleShowSidePanel = usePreferencesStore(state => state.toggleShowOssSidePanel);
|
||||
|
||||
const selectedOperation =
|
||||
selectedItems.length === 1 && selectedItems[0].nodeType === NodeType.OPERATION ? selectedItems[0] : null;
|
||||
const selectedBlock =
|
||||
selectedItems.length === 1 && selectedItems[0].nodeType === NodeType.BLOCK ? selectedItems[0] : null;
|
||||
|
||||
function handleMenuToggle() {
|
||||
hideContextMenu();
|
||||
menu.toggle();
|
||||
}
|
||||
|
||||
function handleShowOptions() {
|
||||
showOptions();
|
||||
}
|
||||
|
@ -127,40 +143,80 @@ export function ToolbarOssGraph({
|
|||
<BadgeHelp topic={HelpTopic.UI_OSS_GRAPH} contentClass='sm:max-w-160' offset={4} />
|
||||
</div>
|
||||
{isMutable ? (
|
||||
<div className='cc-icons'>
|
||||
<div className='cc-icons items-start'>
|
||||
<MiniButton
|
||||
titleHtml={prepareTooltip('Сохранить изменения', 'Ctrl + S')}
|
||||
aria-label='Сохранить изменения'
|
||||
titleHtml={prepareTooltip('Сохранить изменения', isMac() ? '⌘ + S' : 'Ctrl + S')}
|
||||
hideTitle={menu.isOpen}
|
||||
icon={<IconSave size='1.25rem' className='icon-primary' />}
|
||||
onClick={handleSavePositions}
|
||||
disabled={isProcessing}
|
||||
/>
|
||||
<MiniButton
|
||||
titleHtml={prepareTooltip('Редактировать выбранную', isIOS() ? '' : 'Правый клик')}
|
||||
hideTitle={isContextMenuOpen}
|
||||
aria-label='Редактировать выбранную'
|
||||
titleHtml={prepareTooltip('Редактировать выбранную', isIOS() ? '' : 'Правый клик')}
|
||||
hideTitle={isContextMenuOpen || menu.isOpen}
|
||||
icon={<IconEdit2 size='1.25rem' className='icon-primary' />}
|
||||
onClick={handleEditItem}
|
||||
disabled={selectedItems.length !== 1 || isProcessing}
|
||||
/>
|
||||
<div ref={menu.ref} onBlur={menu.handleBlur} className='relative'>
|
||||
<MiniButton
|
||||
title='Добавить...'
|
||||
hideTitle={menu.isOpen}
|
||||
icon={<IconNewItem size='1.25rem' className='icon-green' />}
|
||||
onClick={handleMenuToggle}
|
||||
disabled={isProcessing}
|
||||
/>
|
||||
<Dropdown isOpen={menu.isOpen} className='-translate-x-1/2'>
|
||||
<DropdownButton
|
||||
text='Новый блок'
|
||||
titleHtml={prepareTooltip('Новый блок', 'Alt + 1')}
|
||||
icon={<IconConceptBlock size='1.25rem' className='text-constructive' />}
|
||||
onClick={onCreateBlock}
|
||||
/>
|
||||
<DropdownButton
|
||||
text='Новая КС'
|
||||
titleHtml={prepareTooltip('Новая концептуальная схема', 'Alt + 2')}
|
||||
icon={<IconNewItem size='1.25rem' className='text-constructive' />}
|
||||
onClick={onCreateSchema}
|
||||
/>
|
||||
<DropdownButton
|
||||
text='Импорт КС'
|
||||
titleHtml={prepareTooltip('Импорт концептуальной схемы', 'Alt + 3')}
|
||||
icon={<IconDownload size='1.25rem' className='text-constructive' />}
|
||||
onClick={onImportSchema}
|
||||
/>
|
||||
<DropdownButton
|
||||
text='Синтез'
|
||||
titleHtml={prepareTooltip('Синтез концептуальных схем', 'Alt + 4')}
|
||||
icon={<IconConceptBlock size='1.25rem' className='text-primary' />}
|
||||
onClick={onCreateSynthesis}
|
||||
/>
|
||||
{user.is_staff ? (
|
||||
<DropdownButton
|
||||
disabled
|
||||
text='Фильтр'
|
||||
titleHtml={prepareTooltip('Фильтрация конституент', 'Alt + 5')}
|
||||
icon={<IconFilter size='1.25rem' className='icon-primary' />}
|
||||
onClick={notImplemented}
|
||||
/>
|
||||
) : null}
|
||||
{user.is_staff ? (
|
||||
<DropdownButton
|
||||
disabled
|
||||
text='Релятивизация'
|
||||
titleHtml={prepareTooltip('Релятивизация концептуальных схем', 'Alt + 6')}
|
||||
icon={<IconClustering size='1.25rem' className='icon-primary' />}
|
||||
onClick={notImplemented}
|
||||
/>
|
||||
) : null}
|
||||
</Dropdown>
|
||||
</div>
|
||||
<MiniButton
|
||||
titleHtml={prepareTooltip('Новая операция', 'Ctrl + Q')}
|
||||
aria-label='Новая операция'
|
||||
icon={<IconNewItem size='1.25rem' className='icon-green' />}
|
||||
onClick={onCreateOperation}
|
||||
disabled={isProcessing}
|
||||
/>
|
||||
<MiniButton
|
||||
titleHtml={prepareTooltip('Новый блок', 'Ctrl + Shift + Q')}
|
||||
aria-label='Новый блок'
|
||||
icon={<IconConceptBlock size='1.25rem' className='icon-green' />}
|
||||
onClick={onCreateBlock}
|
||||
disabled={isProcessing}
|
||||
/>
|
||||
|
||||
<MiniButton
|
||||
titleHtml={prepareTooltip('Удалить выбранную', 'Delete')}
|
||||
aria-label='Удалить выбранную'
|
||||
titleHtml={prepareTooltip('Удалить выбранную', 'Delete')}
|
||||
hideTitle={menu.isOpen}
|
||||
icon={<IconDestroy size='1.25rem' className='icon-red' />}
|
||||
onClick={onDelete}
|
||||
disabled={
|
||||
|
|
|
@ -4,6 +4,7 @@ import { hoverTooltip, type TooltipView } from '@codemirror/view';
|
|||
import clsx from 'clsx';
|
||||
|
||||
import { findContainedNodes } from '@/utils/codemirror';
|
||||
import { isMac } from '@/utils/utils';
|
||||
|
||||
import { describeConstituentaTerm, labelGrammeme } from '../../labels';
|
||||
import { type IEntityReference, type ISyntacticReference } from '../../models/language';
|
||||
|
@ -95,7 +96,9 @@ function domTooltipEntityReference(ref: IEntityReference, cst: IConstituenta | n
|
|||
if (canClick) {
|
||||
const clickTip = document.createElement('p');
|
||||
clickTip.className = 'text-center text-xs mt-1';
|
||||
clickTip.innerHTML = '<kbd>Ctrl + клик</kbd> для перехода</br><kbd>Ctrl + пробел</kbd> для редактирования';
|
||||
clickTip.innerHTML = isMac()
|
||||
? '<kbd>Cmd + клик</kbd> для перехода</br><kbd>Cmd + пробел</kbd> для редактирования'
|
||||
: '<kbd>Ctrl + клик</kbd> для перехода</br><kbd>Ctrl + пробел</kbd> для редактирования';
|
||||
dom.appendChild(clickTip);
|
||||
}
|
||||
|
||||
|
@ -140,7 +143,9 @@ function domTooltipSyntacticReference(
|
|||
if (canClick) {
|
||||
const clickTip = document.createElement('p');
|
||||
clickTip.className = 'text-center text-xs mt-1';
|
||||
clickTip.innerHTML = '<kbd>Ctrl + пробел</kbd> для редактирования';
|
||||
clickTip.innerHTML = isMac()
|
||||
? '<kbd>Cmd + пробел</kbd> для редактирования'
|
||||
: '<kbd>Ctrl + пробел</kbd> для редактирования';
|
||||
dom.appendChild(clickTip);
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ import { cn } from '@/components/utils';
|
|||
import { useModificationStore } from '@/stores/modification';
|
||||
import { usePreferencesStore } from '@/stores/preferences';
|
||||
import { tooltipText } from '@/utils/labels';
|
||||
import { prepareTooltip } from '@/utils/utils';
|
||||
import { isMac, prepareTooltip } from '@/utils/utils';
|
||||
|
||||
import { useMutatingRSForm } from '../../../backend/use-mutating-rsform';
|
||||
import { type IConstituenta } from '../../../models/rsform';
|
||||
|
@ -97,7 +97,7 @@ export function ToolbarConstituenta({
|
|||
{isContentEditable ? (
|
||||
<>
|
||||
<MiniButton
|
||||
titleHtml={prepareTooltip('Сохранить изменения', 'Ctrl + S')}
|
||||
titleHtml={prepareTooltip('Сохранить изменения', isMac() ? 'Cmd + S' : 'Ctrl + S')}
|
||||
aria-label='Сохранить изменения'
|
||||
icon={<IconSave size='1.25rem' className='icon-primary' />}
|
||||
onClick={onSubmit}
|
||||
|
|
|
@ -10,7 +10,7 @@ import { cn } from '@/components/utils';
|
|||
import { APP_COLORS } from '@/styling/colors';
|
||||
import { globalIDs } from '@/utils/constants';
|
||||
import { type RO } from '@/utils/meta';
|
||||
import { prepareTooltip } from '@/utils/utils';
|
||||
import { isMac, prepareTooltip } from '@/utils/utils';
|
||||
|
||||
import { type IExpressionParseDTO, ParsingStatus } from '../../../backend/types';
|
||||
import { colorStatusBar } from '../../../colors';
|
||||
|
@ -55,7 +55,7 @@ export function StatusBar({ className, isModified, processing, activeCst, parseD
|
|||
)}
|
||||
style={{ backgroundColor: processing ? APP_COLORS.bgDefault : colorStatusBar(status) }}
|
||||
data-tooltip-id={globalIDs.tooltip}
|
||||
data-tooltip-html={prepareTooltip('Проверить определение', 'Ctrl + Q')}
|
||||
data-tooltip-html={prepareTooltip('Проверить определение', isMac() ? 'Cmd + Q' : 'Ctrl + Q')}
|
||||
onClick={onAnalyze}
|
||||
>
|
||||
{processing ? (
|
||||
|
|
|
@ -176,6 +176,25 @@ export function sharePage() {
|
|||
.catch(console.error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show error message about not implemented function.
|
||||
*/
|
||||
export function notImplemented() {
|
||||
toast.error('Данная функция еще не реализована');
|
||||
console.error('Not implemented');
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap event handler to prevent default and stop propagation.
|
||||
*/
|
||||
export function withPreventDefault<T extends React.SyntheticEvent>(handler: (event: T) => void) {
|
||||
return (event: T) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
handler(event);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove html tags from target string.
|
||||
*/
|
||||
|
@ -196,12 +215,22 @@ export function prepareTooltip(text: string, hotkey?: string) {
|
|||
/**
|
||||
* Utility to detect iOS/iPadOS.
|
||||
*/
|
||||
export function isIOS() {
|
||||
export function isIOS(): boolean {
|
||||
if (typeof navigator === 'undefined') {
|
||||
return false;
|
||||
}
|
||||
return (
|
||||
/iPad|iPhone|iPod/.test(navigator.userAgent) ||
|
||||
/iPad|iPhone|iPod/i.test(navigator.userAgent) ||
|
||||
(navigator.userAgent.includes('Macintosh') && 'ontouchend' in document)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility to detect Mac device.
|
||||
*/
|
||||
export function isMac(): boolean {
|
||||
if (typeof navigator === 'undefined') {
|
||||
return false;
|
||||
}
|
||||
return /Macintosh|MacIntel|MacPPC|Mac68K|Mac OS/i.test(navigator.userAgent);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user