Commit d131f8a5 authored by Яков's avatar Яков
Browse files

Панель инструментов: новый набор иконок и состояния



Ответ на макет: 56 иконок в одном визуальном языке (сетка 24×24, штрих 1.5),
шесть состояний кнопки, ритм групп, поведение на телефоне.

Главная правка не косметическая. Иконка перестала быть background-image
с зашитым цветом и стала дочерним <svg> со stroke="currentColor". Без этого
не собирались сами состояния: наведение приходилось изображать прозрачностью
(иконка тускнела — читается как «кнопка выключилась»), а активное состояние
с белой иконкой на синей подложке было невозможно в принципе.

Заодно ушли ручные подпорки, которые были следствием разнокалиберных картинок:
width 46px у блока кода, margin-top 4px у PPTX, второй вид разделителя.
Все кнопки теперь 32×32 на десктопе и 44×44 на телефоне.

Четыре кнопки, использованные на боевой базе ноль раз (аудио, картинка
с подсказками, скрытый блок, кнопка-ссылка), собраны в подписанную группу
«Оживить урок»: растворённые между «изображением» и «ссылкой», они
не читались как отдельная возможность.

Горизонтальной прокрутки на телефоне нет намеренно: скрытая справа кнопка
не находится вообще — методист не знает, что там что-то есть.
Co-Authored-By: default avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
parent 1d0665b4
...@@ -40,6 +40,7 @@ import InteractiveImage from './extensions/InteractiveImage' ...@@ -40,6 +40,7 @@ import InteractiveImage from './extensions/InteractiveImage'
import FontSize from './extensions/FontSize' import FontSize from './extensions/FontSize'
import BlockId from './extensions/BlockId' import BlockId from './extensions/BlockId'
import ActivityRef from './extensions/ActivityRef' import ActivityRef from './extensions/ActivityRef'
import { Icon } from './icons'
import ButtonLinkExtension from './extensions/ButtonLink' import ButtonLinkExtension from './extensions/ButtonLink'
// import Image from '@tiptap/extension-image' // import Image from '@tiptap/extension-image'
...@@ -2094,9 +2095,7 @@ const QEditor = ({ ...@@ -2094,9 +2095,7 @@ const QEditor = ({
return ( return (
<div <div
key={'bubbleItems-glossary'} key={'bubbleItems-glossary'}
className={ className={'qicon'}
'qicon qglossary'
}
title={'Добавить в глоссарий'} title={'Добавить в глоссарий'}
onClick={()=>{ onClick={()=>{
if (!editor.state.selection.empty) { if (!editor.state.selection.empty) {
...@@ -2113,21 +2112,21 @@ const QEditor = ({ ...@@ -2113,21 +2112,21 @@ const QEditor = ({
} }
// console.log(editor.chain().focus()); // console.log(editor.chain().focus());
}} }}
/> >
<Icon type='glossary' />
</div>
) )
} }
} else { } else {
return ( return (
<div <div
key={'bubbleItems' + i} key={'bubbleItems' + i}
className={ className={'qicon' + (editor.isActive(type) ? ' active' : '')}
'qicon q' +
type +
(editor.isActive(type) ? ' active' : '')
}
title={toolsLib[type] ? toolsLib[type].title : ''} title={toolsLib[type] ? toolsLib[type].title : ''}
onClick={toolsLib[type].onClick} onClick={toolsLib[type].onClick}
/> >
<Icon type={type} />
</div>
) )
} }
})} })}
......
import React, { useEffect, useMemo, useRef, useState } from 'react' import React, { useEffect, useMemo, useRef, useState } from 'react'
import { Icon } from '../icons'
const emojiSource = require('emojibase-data/en/data.json') const emojiSource = require('emojibase-data/en/data.json')
...@@ -240,7 +241,7 @@ const EmojiPicker = ({ editor }) => { ...@@ -240,7 +241,7 @@ const EmojiPicker = ({ editor }) => {
className={'atma-editor-toolbar-emoji' + (isOpen ? ' open' : '')} className={'atma-editor-toolbar-emoji' + (isOpen ? ' open' : '')}
> >
<div <div
className={'qicon qemoji' + (isOpen ? ' active' : '')} className={'qicon' + (isOpen ? ' active' : '')}
title='Эмодзи' title='Эмодзи'
onMouseDown={(event) => { onMouseDown={(event) => {
event.preventDefault() event.preventDefault()
...@@ -250,7 +251,9 @@ const EmojiPicker = ({ editor }) => { ...@@ -250,7 +251,9 @@ const EmojiPicker = ({ editor }) => {
event.stopPropagation() event.stopPropagation()
setIsOpen(!isOpen) setIsOpen(!isOpen)
}} }}
/> >
<Icon type='emoji' />
</div>
{isOpen && ( {isOpen && (
<div <div
className='atma-editor-emoji-popover' className='atma-editor-emoji-popover'
......
import React, { Fragment, useState } from 'react'; import React, { Fragment, useState } from 'react';
import { Tooltip } from 'antd'; import { Tooltip } from 'antd';
import { Icon } from '../icons';
// ───────────────────────────────────────────────────────────────────────────── // ─────────────────────────────────────────────────────────────────────────────
...@@ -42,7 +43,7 @@ const LESSON = [ ...@@ -42,7 +43,7 @@ const LESSON = [
HEADINGS, HEADINGS,
{ type: 'g', items: ['|'] }, { type: 'g', items: ['|'] },
{ type: 's', toggle: false, items: ['bulletList', 'orderedList', 'insertToggleBlock'] }, { type: 's', toggle: false, items: ['bulletList', 'orderedList'] },
{ type: 's', toggle: true, items: ['alignLeft', 'alignCenter', 'alignRight'] }, { type: 's', toggle: true, items: ['alignLeft', 'alignCenter', 'alignRight'] },
TABLE_GROUP, TABLE_GROUP,
...@@ -53,17 +54,34 @@ const LESSON = [ ...@@ -53,17 +54,34 @@ const LESSON = [
{ type: 'g', items: ['|'] }, { type: 'g', items: ['|'] },
{ type: 'g', items: ['activityRef'] }, { type: 'g', items: ['activityRef'] },
{ type: 's', toggle: false, items: ['image', 'interactiveImage'] }, { type: 's', toggle: false, items: ['image'] },
{ type: 's', toggle: false, items: ['video', 'iframe'] }, { type: 's', toggle: false, items: ['video', 'iframe'] },
{ type: 'g', items: ['audio'] },
{ type: 'g', items: ['voicemessage'] }, { type: 'g', items: ['voicemessage'] },
{ type: 'g', items: ['webcamera'] }, { type: 'g', items: ['webcamera'] },
{ type: 'g', items: ['screencust'] }, { type: 'g', items: ['screencust'] },
{ type: 'g', items: ['|'] }, { type: 'g', items: ['|'] },
// ── «Оживить урок» ───────────────────────────────────────────────────────
//
// Четыре кнопки: аудио, картинка с подсказками, скрытый блок,
// кнопка-ссылка. На боевой базе клиента (601 урок) каждая использована
// НОЛЬ раз, хотя все работают.
//
// Иконку и подсказку они уже получили — не помогло бы: растворённые между
// «изображением» и «ссылкой», они не читаются как отдельная возможность.
// Поэтому у них своя группа с подписью. Мера бесплатная и делает
// необязательными дорогие: разовую подсветку новинки и карточки-примеры
// в пустом уроке.
//
// Подпись показывается только на широком экране — см. LABEL_MIN_WIDTH.
{ type: 'g', label: 'Оживить урок',
items: ['audio', 'interactiveImage', 'insertToggleBlock', 'buttonLink'] },
{ type: 'g', items: ['|'] },
{ type: 's', toggle: false, items: ['iframe_pptx', 'iframe_pdf', 'pdf'] }, { type: 's', toggle: false, items: ['iframe_pptx', 'iframe_pdf', 'pdf'] },
{ type: 's', toggle: false, items: ['link', 'buttonLink'] }, { type: 'g', items: ['link'] },
{ type: 'g', items: ['file'] }, { type: 'g', items: ['file'] },
{ type: 'g', items: ['iframe_custom'] }, { type: 'g', items: ['iframe_custom'] },
{ type: 'g', items: ['export_pdf'] }, { type: 'g', items: ['export_pdf'] },
...@@ -347,7 +365,7 @@ const ToolBar = ({ editor, toolsLib = [], toolsOptions, onInfo, labels = {} }) = ...@@ -347,7 +365,7 @@ const ToolBar = ({ editor, toolsLib = [], toolsOptions, onInfo, labels = {} }) =
data-type={type} data-type={type}
> >
<Fragment> <Fragment>
<div className={`qicon q${type}`} /> <Icon type={type} />
<span>{infoFor(type, item).title}</span> <span>{infoFor(type, item).title}</span>
</Fragment> </Fragment>
</div> </div>
...@@ -373,12 +391,14 @@ const ToolBar = ({ editor, toolsLib = [], toolsOptions, onInfo, labels = {} }) = ...@@ -373,12 +391,14 @@ const ToolBar = ({ editor, toolsLib = [], toolsOptions, onInfo, labels = {} }) =
e.stopPropagation() e.stopPropagation()
return false; return false;
}} }}
className={`qicon q${type}` + (disabled ? ' disabled' : '')} className={'qicon' + (disabled ? ' disabled' : '')}
role="button" role="button"
tabIndex={disabled ? -1 : 0} tabIndex={disabled ? -1 : 0}
aria-label={undoInfo.title} aria-label={undoInfo.title}
aria-disabled={disabled} aria-disabled={disabled}
/> >
<Icon type={type} />
</div>
</Tooltip> </Tooltip>
) )
} }
...@@ -407,11 +427,14 @@ const ToolBar = ({ editor, toolsLib = [], toolsOptions, onInfo, labels = {} }) = ...@@ -407,11 +427,14 @@ const ToolBar = ({ editor, toolsLib = [], toolsOptions, onInfo, labels = {} }) =
e.stopPropagation() e.stopPropagation()
return false; return false;
}} }}
className={`qicon q${type}` + (isActive(type) ? ' active' : '')} className={'qicon' + (isActive(type) ? ' active' : '')}
role="button" role="button"
tabIndex={0} tabIndex={0}
aria-label={info.title} aria-label={info.title}
/> aria-pressed={isActive(type)}
>
<Icon type={type} />
</div>
</Tooltip> </Tooltip>
) )
} }
...@@ -449,7 +472,16 @@ const ToolBar = ({ editor, toolsLib = [], toolsOptions, onInfo, labels = {} }) = ...@@ -449,7 +472,16 @@ const ToolBar = ({ editor, toolsLib = [], toolsOptions, onInfo, labels = {} }) =
}) })
toolItems.push( toolItems.push(
<div key={`tools-g${i}`} className="atma-editor-toolbar-g">{ gItems }</div> <div key={`tools-g${i}`}
className={'atma-editor-toolbar-g' + (section.label ? ' has-label' : '')}>
{section.label && (
// Подпись группы. Скрывается оформлением на узком
// экране, а не условием в коде: тогда при изменении
// размера окна панель не пересобирается.
<span className="atma-editor-toolbar-g-label">{section.label}</span>
)}
{ gItems }
</div>
) )
} }
...@@ -483,7 +515,9 @@ const ToolBar = ({ editor, toolsLib = [], toolsOptions, onInfo, labels = {} }) = ...@@ -483,7 +515,9 @@ const ToolBar = ({ editor, toolsLib = [], toolsOptions, onInfo, labels = {} }) =
}}> }}>
<Fragment> <Fragment>
{ {
<div className={`qicon q${activeType === false || section.toggle === false ? section.items[0] : activeType}`} /> <div className={'qicon' + (activeType !== false && section.toggle !== false ? ' active' : '')}>
<Icon type={activeType === false || section.toggle === false ? section.items[0] : activeType} />
</div>
} }
<div <div
className={'atma-editor-toolbar-s-opts'} className={'atma-editor-toolbar-s-opts'}
......
import React from 'react'
/**
* Набор иконок панели: 56 штук, один визуальный язык.
*
* ── Почему тут разметка, а не картинки ───────────────────────────────────────
*
* Раньше каждая иконка была `background-image: url("data:image/svg+xml,…")`.
* У такой иконки НЕЛЬЗЯ поменять цвет из CSS — он зашит внутрь строки. Поэтому
* наведение приходилось изображать через `opacity: .8`, то есть иконка тускнела,
* что читается как «кнопка выключилась», а не «сюда можно нажать». А активное
* состояние с белой иконкой на синей подложке было невозможно в принципе.
*
* Теперь иконка — дочерний <svg> со `stroke="currentColor"`: цвет наследуется
* от кнопки, и все шесть состояний собираются одним правилом на `color`.
*
* ── Правила набора ───────────────────────────────────────────────────────────
*
* Сетка 24×24, толщина штриха 1.5, полезная площадь рисунка 20×20, скруглённые
* концы и стыки. Буквы (B, I, U, S) нарисованы контурами того же веса, а не
* взяты из системного шрифта: раньше они выбивались из ряда чужой метрикой.
*
* Хранится ВНУТРЕННОСТЬ svg, обёртку рисует компонент Icon — так не разъедутся
* viewBox и толщина штриха, если кто-то добавит иконку невнимательно.
*
* Макет: docs/redactor/design-reference (в репозитории платформы).
*/
const ICONS = {
activityRef: '<path d="M6 4h12a2.5 2.5 0 0 1 2.5 2.5v11a2.5 2.5 0 0 1 -2.5 2.5h-12a2.5 2.5 0 0 1 -2.5 -2.5v-11a2.5 2.5 0 0 1 2.5 -2.5z"></path><path d="M6.9 9.2l1.7 1.7 3.4-3.5"></path><path d="M14.6 9h3.6"></path><path d="M6.6 15.3a1.5 1.5 0 1 0 3 0a1.5 1.5 0 1 0 -3 0z"></path><path d="M12.3 15.3h5.9"></path>',
addColumnAfter: '<path d="M6 3.5h4.6a2 2 0 0 1 2 2v13a2 2 0 0 1 -2 2h-4.6a2 2 0 0 1 -2 -2v-13a2 2 0 0 1 2 -2z"></path><path d="M4 12h8.6"></path><path d="M18 9.4v5.2"></path><path d="M15.4 12h5.2"></path>',
addColumnBefore: '<path d="M13.4 3.5h4.6a2 2 0 0 1 2 2v13a2 2 0 0 1 -2 2h-4.6a2 2 0 0 1 -2 -2v-13a2 2 0 0 1 2 -2z"></path><path d="M11.4 12h8.6"></path><path d="M6 9.4v5.2"></path><path d="M3.4 12h5.2"></path>',
addRowAfter: '<path d="M5.5 4h13a2 2 0 0 1 2 2v4.6a2 2 0 0 1 -2 2h-13a2 2 0 0 1 -2 -2v-4.6a2 2 0 0 1 2 -2z"></path><path d="M12 4v8.6"></path><path d="M12 15.4v5.2"></path><path d="M9.4 18h5.2"></path>',
addRowBefore: '<path d="M5.5 11.4h13a2 2 0 0 1 2 2v4.6a2 2 0 0 1 -2 2h-13a2 2 0 0 1 -2 -2v-4.6a2 2 0 0 1 2 -2z"></path><path d="M12 11.4v8.6"></path><path d="M12 3.4v5.2"></path><path d="M9.4 6h5.2"></path>',
alignCenter: '<path d="M4.5 6h15"></path><path d="M7.5 10.5h9"></path><path d="M4.5 15h15"></path><path d="M7.5 19.5h9"></path>',
alignLeft: '<path d="M4.5 6h15"></path><path d="M4.5 10.5h9"></path><path d="M4.5 15h15"></path><path d="M4.5 19.5h9"></path>',
alignRight: '<path d="M4.5 6h15"></path><path d="M10.5 10.5h9"></path><path d="M4.5 15h15"></path><path d="M10.5 19.5h9"></path>',
audio: '<path d="M7 8h10a4 4 0 0 1 4 4v0a4 4 0 0 1 -4 4h-10a4 4 0 0 1 -4 -4v0a4 4 0 0 1 4 -4z"></path><path d="M7.2 10.3l2.7 1.7-2.7 1.7z"></path><path d="M12.2 12h6.4"></path><path d="M12.9 12a1.7 1.7 0 1 0 3.4 0a1.7 1.7 0 1 0 -3.4 0z"></path>',
blockquote: '<path d="M5 6.2v11.6" stroke-width="3"></path><path d="M10.4 8h8.6"></path><path d="M10.4 12h8.6"></path><path d="M10.4 16h6"></path>',
bold: '<path d="M8.4 5.6h4.3a3.2 3.2 0 0 1 0 6.4H8.4z"></path><path d="M8.4 12h5.1a3.25 3.25 0 0 1 0 6.5H8.4z"></path>',
bulletList: '<path d="M4.300000000000001 7a1.4 1.4 0 1 0 2.8 0a1.4 1.4 0 1 0 -2.8 0z" fill="currentColor" stroke="none"></path><path d="M4.300000000000001 12a1.4 1.4 0 1 0 2.8 0a1.4 1.4 0 1 0 -2.8 0z" fill="currentColor" stroke="none"></path><path d="M4.300000000000001 17a1.4 1.4 0 1 0 2.8 0a1.4 1.4 0 1 0 -2.8 0z" fill="currentColor" stroke="none"></path><path d="M10.2 7h8.8"></path><path d="M10.2 12h8.8"></path><path d="M10.2 17h8.8"></path>',
buttonLink: '<path d="M7.3999999999999995 7.4h9.2a4.6 4.6 0 0 1 4.6 4.6v0a4.6 4.6 0 0 1 -4.6 4.6h-9.2a4.6 4.6 0 0 1 -4.6 -4.6v0a4.6 4.6 0 0 1 4.6 -4.6z"></path><path d="M6.8 12h5.4"></path><path d="M14.8 12h2.6"></path><path d="M16.2 10.8 17.4 12l-1.2 1.2"></path>',
clearMarks: '<path d="M15.4 5.1l3.5 3.5a1.8 1.8 0 0 1 0 2.6l-8.5 8.5H6.3l-2.7-2.7a1.8 1.8 0 0 1 0-2.6l9.2-9.3a1.8 1.8 0 0 1 2.6 0z"></path><path d="M10.4 20.7H20.5"></path><path d="M8.1 10.2l5.6 5.6"></path>',
codeBlock: '<path d="M6 5h12a2.5 2.5 0 0 1 2.5 2.5v9a2.5 2.5 0 0 1 -2.5 2.5h-12a2.5 2.5 0 0 1 -2.5 -2.5v-9a2.5 2.5 0 0 1 2.5 -2.5z"></path><path d="M9.9 9.9 7.8 12l2.1 2.1"></path><path d="M14.1 9.9 16.2 12l-2.1 2.1"></path>',
colorText: '<path d="M12 4.4c0 0-4.4 5-4.4 8a4.4 4.4 0 0 0 8.8 0c0-3-4.4-8-4.4-8z"></path><path d="M5 20.4h14" stroke-width="3"></path>',
deleteColumn: '<path d="M9.8 4h4.4a1.8 1.8 0 0 1 1.8 1.8v12.4a1.8 1.8 0 0 1 -1.8 1.8h-4.4a1.8 1.8 0 0 1 -1.8 -1.8v-12.4a1.8 1.8 0 0 1 1.8 -1.8z"></path><path d="M12 2.4v19.2" stroke-width="1.9"></path><path d="M4.6 4.6v14.8" stroke-width="1.3"></path><path d="M19.4 4.6v14.8" stroke-width="1.3"></path>',
deleteRow: '<path d="M5.8 8h12.4a1.8 1.8 0 0 1 1.8 1.8v4.4a1.8 1.8 0 0 1 -1.8 1.8h-12.4a1.8 1.8 0 0 1 -1.8 -1.8v-4.4a1.8 1.8 0 0 1 1.8 -1.8z"></path><path d="M2.4 12h19.2" stroke-width="1.9"></path><path d="M4.6 4.6h14.8" stroke-width="1.3"></path><path d="M4.6 19.4h14.8" stroke-width="1.3"></path>',
deleteTable: '<path d="M5 6h10a2 2 0 0 1 2 2v10a2 2 0 0 1 -2 2h-10a2 2 0 0 1 -2 -2v-10a2 2 0 0 1 2 -2z"></path><path d="M3 13h14"></path><path d="M10 6v14"></path><path d="M16.9 4.2l4.7 4.7"></path><path d="M21.6 4.2l-4.7 4.7"></path>',
emoji: '<path d="M4 12a8 8 0 1 0 16 0a8 8 0 1 0 -16 0z"></path><path d="M8.350000000000001 10a0.95 0.95 0 1 0 1.9 0a0.95 0.95 0 1 0 -1.9 0z" fill="currentColor" stroke="none"></path><path d="M13.75 10a0.95 0.95 0 1 0 1.9 0a0.95 0.95 0 1 0 -1.9 0z" fill="currentColor" stroke="none"></path><path d="M8.5 14.3a4.1 4.1 0 0 0 7 0"></path>',
export_pdf: '<path d="M6.3999999999999995 3h11.200000000000001a1.8 1.8 0 0 1 1.8 1.8v5.800000000000001a1.8 1.8 0 0 1 -1.8 1.8h-11.200000000000001a1.8 1.8 0 0 1 -1.8 -1.8v-5.800000000000001a1.8 1.8 0 0 1 1.8 -1.8z"></path><path d="M13.2 3v4.2a1.5 1.5 0 0 0 1.5 1.5h4.7"></path><path d="M12 14v6.6"></path><path d="M8.9 17.5 12 20.6l3.1-3.1"></path>',
file: '<path d="M5.5 6h13a2.5 2.5 0 0 1 2.5 2.5v7a2.5 2.5 0 0 1 -2.5 2.5h-13a2.5 2.5 0 0 1 -2.5 -2.5v-7a2.5 2.5 0 0 1 2.5 -2.5z"></path><path d="M7 9h2.5999999999999996a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-2.5999999999999996a1 1 0 0 1 -1 -1v-4a1 1 0 0 1 1 -1z"></path><path d="M13.2 11h5"></path><path d="M13.2 15h3.2"></path>',
fontSize: '<path d="M6 7.6v8.8"></path><path d="M4 9.6 6 7.6l2 2"></path><path d="M4 14.4l2 2 2-2"></path><path d="M11.5 8h8.5"></path><path d="M11.5 12h8.5"></path><path d="M11.5 16h5"></path>',
glossary: '<path d="M7 3.4h10a2 2 0 0 1 2 2v3a2 2 0 0 1 -2 2h-10a2 2 0 0 1 -2 -2v-3a2 2 0 0 1 2 -2z"></path><path d="M10.9 10.4l1.1 2.2 1.1-2.2"></path><path d="M6.6 16.4h10.8"></path><path d="M6.6 20h10.8" stroke-dasharray="1.8 2.4"></path>',
h2: '<path d="M5 7.2h14" stroke-width="4.6"></path><path d="M5 14.4h13" stroke-width="1.5"></path><path d="M5 19h8.5" stroke-width="1.5"></path>',
h3: '<path d="M5 7.2h9.8" stroke-width="3.6"></path><path d="M5 14.4h13" stroke-width="1.5"></path><path d="M5 19h8.5" stroke-width="1.5"></path>',
h4: '<path d="M5 7.2h6.4" stroke-width="2.6"></path><path d="M5 14.4h13" stroke-width="1.5"></path><path d="M5 19h8.5" stroke-width="1.5"></path>',
hardBreak: '<path d="M20 6.4v5.6a2.5 2.5 0 0 1-2.5 2.5H5"></path><path d="M8.5 11 5 14.5 8.5 18"></path>',
highlight: '<path d="M6.4 6.2h11.2" stroke-width="2.2"></path><path d="M6.6000000000000005 10.4h10.799999999999999a2.2 2.2 0 0 1 2.2 2.2v2.1999999999999993a2.2 2.2 0 0 1 -2.2 2.2h-10.799999999999999a2.2 2.2 0 0 1 -2.2 -2.2v-2.1999999999999993a2.2 2.2 0 0 1 2.2 -2.2z"></path><path d="M7.6 13.7h8.8" stroke-width="2.4"></path><path d="M6.4 20.6h8" stroke-width="2.2"></path>',
hr: '<path d="M5 5.6h14"></path><path d="M5 9h9"></path><path d="M3.5 13h17" stroke-width="2.2"></path><path d="M5 17h14"></path><path d="M5 20.4h6"></path>',
iframe: '<path d="M6 5h12a2.5 2.5 0 0 1 2.5 2.5v9a2.5 2.5 0 0 1 -2.5 2.5h-12a2.5 2.5 0 0 1 -2.5 -2.5v-9a2.5 2.5 0 0 1 2.5 -2.5z"></path><path d="M3.5 9h17"></path><path d="M5.55 7a0.75 0.75 0 1 0 1.5 0a0.75 0.75 0 1 0 -1.5 0z" fill="currentColor" stroke="none"></path><path d="M10.4 11.9l3.6 2.3-3.6 2.3z"></path>',
iframe_custom: '<path d="M6 5h12a2.5 2.5 0 0 1 2.5 2.5v9a2.5 2.5 0 0 1 -2.5 2.5h-12a2.5 2.5 0 0 1 -2.5 -2.5v-9a2.5 2.5 0 0 1 2.5 -2.5z"></path><path d="M3.5 9h17"></path><path d="M5.55 7a0.75 0.75 0 1 0 1.5 0a0.75 0.75 0 1 0 -1.5 0z" fill="currentColor" stroke="none"></path><path d="M9.9 12.4 7.8 14.7l2.1 2.3"></path><path d="M14.1 12.4l2.1 2.3-2.1 2.3"></path>',
iframe_pdf: '<path d="M5.8 3.5h7.4a1.8 1.8 0 0 1 1.8 1.8v13.4a1.8 1.8 0 0 1 -1.8 1.8h-7.4a1.8 1.8 0 0 1 -1.8 -1.8v-13.4a1.8 1.8 0 0 1 1.8 -1.8z"></path><path d="M11 3.5v4h4"></path><path d="M7 12h5" stroke-width="1.3"></path><path d="M7 15.4h4" stroke-width="1.3"></path><path d="M17.9 9.4l2.6 2.6-2.6 2.6"></path>',
iframe_pptx: '<path d="M5.5 4h13a2 2 0 0 1 2 2v7.4a2 2 0 0 1 -2 2h-13a2 2 0 0 1 -2 -2v-7.4a2 2 0 0 1 2 -2z"></path><path d="M7.2 8h7"></path><path d="M7.2 11.3h4.5"></path><path d="M12 15.4v2.7"></path><path d="M8.7 19.7l3.3-1.6 3.3 1.6"></path>',
image: '<path d="M6 5h12a2.5 2.5 0 0 1 2.5 2.5v9a2.5 2.5 0 0 1 -2.5 2.5h-12a2.5 2.5 0 0 1 -2.5 -2.5v-9a2.5 2.5 0 0 1 2.5 -2.5z"></path><path d="M7.199999999999999 9.5a1.4 1.4 0 1 0 2.8 0a1.4 1.4 0 1 0 -2.8 0z" fill="currentColor" stroke="none"></path><path d="M5.1 16.9l4.2-4.7 3 3 2.6-2.6 3.6 4.2"></path>',
insertTable: '<path d="M5.5 5h13a2 2 0 0 1 2 2v10a2 2 0 0 1 -2 2h-13a2 2 0 0 1 -2 -2v-10a2 2 0 0 1 2 -2z"></path><path d="M3.5 9.7h17"></path><path d="M3.5 14.3h17"></path><path d="M9.2 5v14"></path><path d="M14.8 5v14"></path>',
insertToggleBlock: '<path d="M5.5 4.4h13a2 2 0 0 1 2 2v3a2 2 0 0 1 -2 2h-13a2 2 0 0 1 -2 -2v-3a2 2 0 0 1 2 -2z"></path><path d="M9.7 7.1 12 9.4l2.3-2.3"></path><path d="M5 15.4h14"></path><path d="M5 19.6h9"></path>',
interactiveImage: '<path d="M6 5h12a2.5 2.5 0 0 1 2.5 2.5v9a2.5 2.5 0 0 1 -2.5 2.5h-12a2.5 2.5 0 0 1 -2.5 -2.5v-9a2.5 2.5 0 0 1 2.5 -2.5z"></path><path d="M6.299999999999999 9.6a1.9 1.9 0 1 0 3.8 0a1.9 1.9 0 1 0 -3.8 0z"></path><path d="M7.4799999999999995 9.6a0.72 0.72 0 1 0 1.44 0a0.72 0.72 0 1 0 -1.44 0z" fill="currentColor" stroke="none"></path><path d="M13.5 9.6a1.9 1.9 0 1 0 3.8 0a1.9 1.9 0 1 0 -3.8 0z"></path><path d="M14.68 9.6a0.72 0.72 0 1 0 1.44 0a0.72 0.72 0 1 0 -1.44 0z" fill="currentColor" stroke="none"></path><path d="M9.9 15.3a1.9 1.9 0 1 0 3.8 0a1.9 1.9 0 1 0 -3.8 0z"></path><path d="M11.08 15.3a0.72 0.72 0 1 0 1.44 0a0.72 0.72 0 1 0 -1.44 0z" fill="currentColor" stroke="none"></path>',
italic: '<path d="M10.6 5.6h6.4"></path><path d="M7 18.4h6.4"></path><path d="M14.3 5.6 9.7 18.4"></path>',
link: '<path d="M10.2 13.4a4.6 4.6 0 0 0 6.9.5l2.7-2.7a4.6 4.6 0 0 0-6.5-6.5l-1.6 1.6"></path><path d="M13.8 10.6a4.6 4.6 0 0 0-6.9-.5l-2.7 2.7a4.6 4.6 0 0 0 6.5 6.5l1.6-1.6"></path>',
mergeOrSplit: '<path d="M5.5 6h13a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-13a2 2 0 0 1 -2 -2v-8a2 2 0 0 1 2 -2z"></path><path d="M12 6v3"></path><path d="M12 15v3"></path><path d="M6.6 12h10.8"></path><path d="M9.1 9.5 6.6 12l2.5 2.5"></path><path d="M14.9 9.5 17.4 12l-2.5 2.5"></path>',
orderedList: '<path d="M4.9 6.2l.95-.7v3" stroke-width="1.1"></path><path d="M4.45 11.15a1.02 1.02 0 0 1 1.95.45c0 .75-1.95 1.35-1.95 1.95h2.1" stroke-width="1.1"></path><path d="M4.6 16.1a1 1 0 0 1 1.85.4c0 .5-.45.8-.9.8.5 0 1 .35 1 .9a1.05 1.05 0 0 1-1.95.4" stroke-width="1.1"></path><path d="M10.2 7h8.8"></path><path d="M10.2 12h8.8"></path><path d="M10.2 17h8.8"></path>',
paragraph: '<path d="M8.6 5.6h10.4" stroke-width="1.6"></path><path d="M5 10.2h14" stroke-width="1.6"></path><path d="M5 14.8h14" stroke-width="1.6"></path><path d="M5 19.4h8" stroke-width="1.6"></path>',
pdf: '<path d="M5 11.4V4.8A1.8 1.8 0 0 1 6.8 3h6.4L19 8.8v2.6"></path><path d="M13.2 3v4.2a1.5 1.5 0 0 0 1.5 1.5H19"></path><path d="M4.6 14.9h14.8"></path><path d="M4.6 17.9h14.8"></path><path d="M4.6 20.9h9"></path>',
redo: '<path d="M19.5 8.5H8.7a4.75 4.75 0 0 0 0 9.5h6.7"></path><path d="M15.6 5l3.9 3.5-3.9 3.5"></path>',
screencust: '<path d="M5 4.5h14a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2v-8a2 2 0 0 1 2 -2z"></path><path d="M12 16.5v3.3"></path><path d="M8.4 19.8h7.2"></path><path d="M9.3 10.5a2.7 2.7 0 1 0 5.4 0a2.7 2.7 0 1 0 -5.4 0z"></path><path d="M11 10.5a1 1 0 1 0 2 0a1 1 0 1 0 -2 0z" fill="currentColor" stroke="none"></path>',
strike: '<path d="M16 8.4a3.9 3.9 0 0 0-7 1.1c0 3.6 7 2.2 7 5.7a3.9 3.9 0 0 1-7.2 1.3"></path><path d="M4.4 12h15.2" stroke-width="1.6"></path>',
subscript: '<path d="M6.4 4.4h5.199999999999999a2 2 0 0 1 2 2v5.199999999999999a2 2 0 0 1 -2 2h-5.199999999999999a2 2 0 0 1 -2 -2v-5.199999999999999a2 2 0 0 1 2 -2z"></path><path d="M16.8 15h1.7999999999999998a1.4 1.4 0 0 1 1.4 1.4v1.7999999999999998a1.4 1.4 0 0 1 -1.4 1.4h-1.7999999999999998a1.4 1.4 0 0 1 -1.4 -1.4v-1.7999999999999998a1.4 1.4 0 0 1 1.4 -1.4z"></path>',
superscript: '<path d="M6.4 10.4h5.199999999999999a2 2 0 0 1 2 2v5.199999999999999a2 2 0 0 1 -2 2h-5.199999999999999a2 2 0 0 1 -2 -2v-5.199999999999999a2 2 0 0 1 2 -2z"></path><path d="M16.8 4.4h1.7999999999999998a1.4 1.4 0 0 1 1.4 1.4v1.7999999999999998a1.4 1.4 0 0 1 -1.4 1.4h-1.7999999999999998a1.4 1.4 0 0 1 -1.4 -1.4v-1.7999999999999998a1.4 1.4 0 0 1 1.4 -1.4z"></path>',
toggleHeaderCell: '<path d="M5.5 5h13a2 2 0 0 1 2 2v10a2 2 0 0 1 -2 2h-13a2 2 0 0 1 -2 -2v-10a2 2 0 0 1 2 -2z"></path><path d="M3.5 10h17"></path><path d="M9.2 10v9"></path><path d="M14.8 10v9"></path><path d="M5.6 7.5h12.8" stroke-width="3"></path>',
toggleTableBorders: '<path d="M5.5 5h13a2 2 0 0 1 2 2v10a2 2 0 0 1 -2 2h-13a2 2 0 0 1 -2 -2v-10a2 2 0 0 1 2 -2z"></path><path d="M3.5 12h17" stroke-dasharray="1.8 2.4"></path><path d="M12 5v14" stroke-dasharray="1.8 2.4"></path>',
underline: '<path d="M7.6 5.4v6.9a4.4 4.4 0 0 0 8.8 0V5.4"></path><path d="M6.2 20.2h11.6" stroke-width="1.6"></path>',
undo: '<path d="M4.5 8.5h10.8a4.75 4.75 0 0 1 0 9.5H8.6"></path><path d="M8.4 5 4.5 8.5 8.4 12"></path>',
video: '<path d="M5.2 5.5h13.6a2.2 2.2 0 0 1 2.2 2.2v8.6a2.2 2.2 0 0 1 -2.2 2.2h-13.6a2.2 2.2 0 0 1 -2.2 -2.2v-8.6a2.2 2.2 0 0 1 2.2 -2.2z"></path><path d="M7.2 5.5v13"></path><path d="M16.8 5.5v13"></path><path d="M3 12h4.2"></path><path d="M16.8 12h4.2"></path><path d="M10.6 9.5l3.6 2.5-3.6 2.5z"></path>',
voicemessage: '<path d="M12 3.4h0a2.6 2.6 0 0 1 2.6 2.6v4.3999999999999995a2.6 2.6 0 0 1 -2.6 2.6h0a2.6 2.6 0 0 1 -2.6 -2.6v-4.3999999999999995a2.6 2.6 0 0 1 2.6 -2.6z"></path><path d="M6.5 11.6a5.5 5.5 0 0 0 11 0"></path><path d="M12 17.1v3.3"></path><path d="M9 20.4h6"></path>',
webcamera: '<path d="M6 6h12a2.5 2.5 0 0 1 2.5 2.5v7a2.5 2.5 0 0 1 -2.5 2.5h-12a2.5 2.5 0 0 1 -2.5 -2.5v-7a2.5 2.5 0 0 1 2.5 -2.5z"></path><path d="M8.7 12a3.3 3.3 0 1 0 6.6 0a3.3 3.3 0 1 0 -6.6 0z"></path><path d="M16.3 8.7a0.8 0.8 0 1 0 1.6 0a0.8 0.8 0 1 0 -1.6 0z" fill="currentColor" stroke="none"></path>',
}
export default ICONS
/**
* Иконка панели.
*
* Обёртка одна на весь набор: viewBox, толщина штриха и скругления заданы
* здесь, а не в каждом файле. Добавили иконку не по сетке — она всё равно
* нарисуется в общем масштабе.
*
* Рисунок 20×20 внутри кнопки 32×32 — полезная площадь из макета.
*/
export const Icon = ({ type, size = 20 }) => {
const body = ICONS[type]
if (!body) {
return null
}
return (
<svg
className="qicon-svg"
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
aria-hidden="true"
focusable="false"
dangerouslySetInnerHTML={{ __html: body }}
/>
)
}
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment