@sequent-org/moodboard 1.3.4 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +6 -1
- package/src/assets/icons/mindmap.svg +3 -0
- package/src/core/SaveManager.js +44 -15
- package/src/core/commands/MindmapStatePatchCommand.js +85 -0
- package/src/core/commands/UpdateContentCommand.js +47 -4
- package/src/core/flows/LayerAndViewportFlow.js +87 -14
- package/src/core/flows/ObjectLifecycleFlow.js +7 -2
- package/src/core/flows/SaveFlow.js +10 -7
- package/src/core/flows/TransformFlow.js +2 -2
- package/src/core/index.js +81 -11
- package/src/core/rendering/ObjectRenderer.js +7 -2
- package/src/grid/BaseGrid.js +65 -0
- package/src/grid/CrossGrid.js +89 -24
- package/src/grid/CrossGridZoomPhases.js +167 -0
- package/src/grid/DotGrid.js +117 -34
- package/src/grid/DotGridZoomPhases.js +214 -16
- package/src/grid/GridDiagnostics.js +80 -0
- package/src/grid/GridFactory.js +13 -11
- package/src/grid/LineGrid.js +176 -37
- package/src/grid/LineGridZoomPhases.js +163 -0
- package/src/grid/ScreenGridPhaseMachine.js +51 -0
- package/src/mindmap/MindmapCompoundContract.js +235 -0
- package/src/moodboard/ActionHandler.js +1 -0
- package/src/moodboard/DataManager.js +57 -0
- package/src/moodboard/bootstrap/MoodBoardUiFactory.js +21 -0
- package/src/moodboard/integration/MoodBoardEventBindings.js +26 -1
- package/src/moodboard/lifecycle/MoodBoardDestroyer.js +15 -0
- package/src/objects/MindmapObject.js +76 -0
- package/src/objects/ObjectFactory.js +3 -1
- package/src/services/BoardService.js +127 -31
- package/src/services/GridSnapResolver.js +60 -0
- package/src/services/MiroZoomLevels.js +39 -0
- package/src/services/SettingsApplier.js +0 -4
- package/src/services/ZoomPanController.js +51 -32
- package/src/tools/object-tools/PlacementTool.js +12 -3
- package/src/tools/object-tools/SelectTool.js +11 -1
- package/src/tools/object-tools/placement/GhostController.js +100 -1
- package/src/tools/object-tools/placement/PlacementEventsBridge.js +2 -0
- package/src/tools/object-tools/placement/PlacementInputRouter.js +2 -2
- package/src/tools/object-tools/selection/FileNameInlineEditorController.js +2 -2
- package/src/tools/object-tools/selection/InlineEditorController.js +15 -0
- package/src/tools/object-tools/selection/MindmapInlineEditorController.js +716 -0
- package/src/tools/object-tools/selection/SelectInputRouter.js +6 -0
- package/src/tools/object-tools/selection/SelectToolSetup.js +2 -0
- package/src/tools/object-tools/selection/TextEditorLifecycleRegistry.js +12 -16
- package/src/ui/ContextMenu.js +6 -6
- package/src/ui/DotGridDebugPanel.js +253 -0
- package/src/ui/HtmlTextLayer.js +1 -1
- package/src/ui/TextPropertiesPanel.js +2 -2
- package/src/ui/handles/GroupSelectionHandlesController.js +4 -1
- package/src/ui/handles/HandlesDomRenderer.js +1486 -15
- package/src/ui/handles/HandlesEventBridge.js +49 -5
- package/src/ui/handles/HandlesInteractionController.js +4 -4
- package/src/ui/mindmap/MindmapConnectionLayer.js +239 -0
- package/src/ui/mindmap/MindmapHtmlTextLayer.js +285 -0
- package/src/ui/mindmap/MindmapLayoutConfig.js +29 -0
- package/src/ui/mindmap/MindmapTextOverlayAdapter.js +144 -0
- package/src/ui/styles/toolbar.css +1 -0
- package/src/ui/styles/workspace.css +100 -0
- package/src/ui/toolbar/ToolbarActionRouter.js +35 -0
- package/src/ui/toolbar/ToolbarPopupsController.js +6 -6
- package/src/ui/toolbar/ToolbarRenderer.js +1 -0
- package/src/ui/toolbar/ToolbarStateController.js +1 -0
- package/src/utils/iconLoader.js +10 -4
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { Events } from '../../core/events/Events.js';
|
|
2
|
+
|
|
3
|
+
const MINDMAP_DRAG_THRESHOLD_PX = 4;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Изолирует mindmap-специфику HTML-слоя текста:
|
|
7
|
+
* - внешний вид overlay-элемента
|
|
8
|
+
* - вход в режим редактирования по клику на текст
|
|
9
|
+
*/
|
|
10
|
+
export class MindmapTextOverlayAdapter {
|
|
11
|
+
supportsObject(objectData) {
|
|
12
|
+
return objectData?.type === 'mindmap';
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
getDefaultFontFamily(objectData) {
|
|
16
|
+
return objectData?.properties?.fontFamily || objectData?.fontFamily || 'Roboto, Arial, sans-serif';
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
applyElementStyles(el) {
|
|
20
|
+
el.classList.add('mb-text--mindmap');
|
|
21
|
+
el.style.pointerEvents = 'none';
|
|
22
|
+
el.style.cursor = 'default';
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
attachEditOnClick({ el, targetEl, objectId, objectData, eventBus }) {
|
|
26
|
+
const clickableEl = targetEl || el;
|
|
27
|
+
let pendingPointer = null;
|
|
28
|
+
let dragStarted = false;
|
|
29
|
+
let suppressNextClick = false;
|
|
30
|
+
|
|
31
|
+
const getCanvasEl = () => {
|
|
32
|
+
const doc = clickableEl?.ownerDocument || document;
|
|
33
|
+
return doc.querySelector('.moodboard-workspace__canvas canvas');
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const dispatchMouseToCanvas = (type, sourceEvent, coords = null) => {
|
|
37
|
+
const canvas = getCanvasEl();
|
|
38
|
+
if (!canvas || !sourceEvent) return;
|
|
39
|
+
const point = coords || { clientX: sourceEvent.clientX, clientY: sourceEvent.clientY };
|
|
40
|
+
const evt = new MouseEvent(type, {
|
|
41
|
+
bubbles: true,
|
|
42
|
+
cancelable: true,
|
|
43
|
+
clientX: point.clientX,
|
|
44
|
+
clientY: point.clientY,
|
|
45
|
+
button: sourceEvent.button || 0,
|
|
46
|
+
buttons: sourceEvent.buttons || 0,
|
|
47
|
+
ctrlKey: !!sourceEvent.ctrlKey,
|
|
48
|
+
metaKey: !!sourceEvent.metaKey,
|
|
49
|
+
shiftKey: !!sourceEvent.shiftKey,
|
|
50
|
+
altKey: !!sourceEvent.altKey,
|
|
51
|
+
});
|
|
52
|
+
canvas.dispatchEvent(evt);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const onWindowMouseMove = (moveEvent) => {
|
|
56
|
+
if (!pendingPointer) return;
|
|
57
|
+
const dx = moveEvent.clientX - pendingPointer.clientX;
|
|
58
|
+
const dy = moveEvent.clientY - pendingPointer.clientY;
|
|
59
|
+
const movedEnough = Math.hypot(dx, dy) >= MINDMAP_DRAG_THRESHOLD_PX;
|
|
60
|
+
if (!dragStarted && movedEnough) {
|
|
61
|
+
dragStarted = true;
|
|
62
|
+
suppressNextClick = true;
|
|
63
|
+
dispatchMouseToCanvas('mousedown', pendingPointer, pendingPointer);
|
|
64
|
+
}
|
|
65
|
+
if (dragStarted) {
|
|
66
|
+
dispatchMouseToCanvas('mousemove', moveEvent);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const onWindowMouseUp = (upEvent) => {
|
|
71
|
+
if (!pendingPointer) return;
|
|
72
|
+
if (dragStarted) {
|
|
73
|
+
dispatchMouseToCanvas('mouseup', upEvent);
|
|
74
|
+
}
|
|
75
|
+
pendingPointer = null;
|
|
76
|
+
dragStarted = false;
|
|
77
|
+
window.removeEventListener('mousemove', onWindowMouseMove, true);
|
|
78
|
+
window.removeEventListener('mouseup', onWindowMouseUp, true);
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const onTextMouseDown = (event) => {
|
|
82
|
+
if (event.button !== 0) return;
|
|
83
|
+
pendingPointer = {
|
|
84
|
+
clientX: event.clientX,
|
|
85
|
+
clientY: event.clientY,
|
|
86
|
+
button: event.button,
|
|
87
|
+
buttons: event.buttons || 1,
|
|
88
|
+
ctrlKey: !!event.ctrlKey,
|
|
89
|
+
metaKey: !!event.metaKey,
|
|
90
|
+
shiftKey: !!event.shiftKey,
|
|
91
|
+
altKey: !!event.altKey,
|
|
92
|
+
};
|
|
93
|
+
dragStarted = false;
|
|
94
|
+
window.addEventListener('mousemove', onWindowMouseMove, true);
|
|
95
|
+
window.addEventListener('mouseup', onWindowMouseUp, true);
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const onTextClick = (event) => {
|
|
99
|
+
if (suppressNextClick) {
|
|
100
|
+
suppressNextClick = false;
|
|
101
|
+
event.preventDefault();
|
|
102
|
+
event.stopPropagation();
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
event.preventDefault();
|
|
106
|
+
event.stopPropagation();
|
|
107
|
+
const actualContent = (typeof el?.dataset?.mbContent === 'string')
|
|
108
|
+
? el.dataset.mbContent
|
|
109
|
+
: (objectData?.properties?.content || objectData?.content || '');
|
|
110
|
+
const posData = { objectId, position: null };
|
|
111
|
+
eventBus.emit(Events.Tool.GetObjectPosition, posData);
|
|
112
|
+
const mergedProperties = {
|
|
113
|
+
...(objectData?.properties || {}),
|
|
114
|
+
content: actualContent,
|
|
115
|
+
};
|
|
116
|
+
if (Number.isFinite(objectData?.width) && !Number.isFinite(mergedProperties.width)) {
|
|
117
|
+
mergedProperties.width = objectData.width;
|
|
118
|
+
}
|
|
119
|
+
if (Number.isFinite(objectData?.height) && !Number.isFinite(mergedProperties.height)) {
|
|
120
|
+
mergedProperties.height = objectData.height;
|
|
121
|
+
}
|
|
122
|
+
eventBus.emit(Events.Tool.ObjectEdit, {
|
|
123
|
+
id: objectId,
|
|
124
|
+
type: 'mindmap',
|
|
125
|
+
position: posData.position || objectData?.position || { x: 0, y: 0 },
|
|
126
|
+
properties: mergedProperties,
|
|
127
|
+
caretClick: {
|
|
128
|
+
clientX: event.clientX,
|
|
129
|
+
clientY: event.clientY,
|
|
130
|
+
},
|
|
131
|
+
create: false,
|
|
132
|
+
});
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
clickableEl.addEventListener('mousedown', onTextMouseDown);
|
|
136
|
+
clickableEl.addEventListener('click', onTextClick);
|
|
137
|
+
return () => {
|
|
138
|
+
window.removeEventListener('mousemove', onWindowMouseMove, true);
|
|
139
|
+
window.removeEventListener('mouseup', onWindowMouseUp, true);
|
|
140
|
+
clickableEl.removeEventListener('mousedown', onTextMouseDown);
|
|
141
|
+
clickableEl.removeEventListener('click', onTextClick);
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
}
|
|
@@ -64,6 +64,7 @@
|
|
|
64
64
|
.moodboard-toolbar__button--attachments:hover,
|
|
65
65
|
.moodboard-toolbar__button--emoji:hover,
|
|
66
66
|
.moodboard-toolbar__button--frame:hover,
|
|
67
|
+
.moodboard-toolbar__button--mindmap:hover,
|
|
67
68
|
.moodboard-toolbar__button--clear:hover,
|
|
68
69
|
.moodboard-toolbar__button--undo:hover:not(:disabled),
|
|
69
70
|
.moodboard-toolbar__button--redo:hover:not(:disabled) { background: #80D8FF !important; }
|
|
@@ -234,6 +234,37 @@
|
|
|
234
234
|
letter-spacing: normal;
|
|
235
235
|
}
|
|
236
236
|
|
|
237
|
+
.mb-text--mindmap {
|
|
238
|
+
display: flex;
|
|
239
|
+
align-items: center;
|
|
240
|
+
justify-content: flex-start;
|
|
241
|
+
text-align: left;
|
|
242
|
+
pointer-events: none;
|
|
243
|
+
cursor: default;
|
|
244
|
+
color: #212121;
|
|
245
|
+
font-family: 'Roboto', Arial, sans-serif;
|
|
246
|
+
font-weight: 400;
|
|
247
|
+
padding-top: 50px;
|
|
248
|
+
padding-bottom: 50px;
|
|
249
|
+
padding-left: 50px;
|
|
250
|
+
padding-right: 50px;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.mb-text--mindmap-content {
|
|
254
|
+
pointer-events: auto;
|
|
255
|
+
display: inline-block;
|
|
256
|
+
max-width: 100%;
|
|
257
|
+
white-space: pre;
|
|
258
|
+
word-break: normal;
|
|
259
|
+
overflow-wrap: normal;
|
|
260
|
+
cursor: default;
|
|
261
|
+
font-weight: 400;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
.mb-text--mindmap-content.is-placeholder {
|
|
265
|
+
opacity: 0.45;
|
|
266
|
+
}
|
|
267
|
+
|
|
237
268
|
/* HTML handles layer */
|
|
238
269
|
.moodboard-html-handles {
|
|
239
270
|
position: absolute;
|
|
@@ -297,6 +328,75 @@
|
|
|
297
328
|
justify-content: center;
|
|
298
329
|
}
|
|
299
330
|
|
|
331
|
+
.mb-mindmap-side-btn {
|
|
332
|
+
position: absolute;
|
|
333
|
+
width: 24px;
|
|
334
|
+
height: 24px;
|
|
335
|
+
border: none;
|
|
336
|
+
border-radius: 50%;
|
|
337
|
+
transform: translate(-50%, -50%);
|
|
338
|
+
display: inline-flex;
|
|
339
|
+
align-items: center;
|
|
340
|
+
justify-content: center;
|
|
341
|
+
background: rgba(107, 114, 128, 0.65);
|
|
342
|
+
color: #ffffff;
|
|
343
|
+
cursor: pointer;
|
|
344
|
+
pointer-events: auto;
|
|
345
|
+
z-index: 13;
|
|
346
|
+
padding: 0;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
.mb-mindmap-side-btn:hover {
|
|
350
|
+
background: #80D8FF;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
.mb-mindmap-side-btn::before,
|
|
354
|
+
.mb-mindmap-side-btn::after {
|
|
355
|
+
content: '';
|
|
356
|
+
position: absolute;
|
|
357
|
+
left: 50%;
|
|
358
|
+
top: 50%;
|
|
359
|
+
background: #ffffff;
|
|
360
|
+
border-radius: 999px;
|
|
361
|
+
transform: translate(-50%, -50%);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
.mb-mindmap-side-btn::before {
|
|
365
|
+
width: 12px;
|
|
366
|
+
height: 2px;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
.mb-mindmap-side-btn::after {
|
|
370
|
+
width: 2px;
|
|
371
|
+
height: 12px;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
.mb-mindmap-side-btn--down {
|
|
375
|
+
font-size: 0;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
.mb-mindmap-side-btn--down::before,
|
|
379
|
+
.mb-mindmap-side-btn--down::after {
|
|
380
|
+
display: block;
|
|
381
|
+
content: '';
|
|
382
|
+
position: absolute;
|
|
383
|
+
left: 50%;
|
|
384
|
+
top: calc(50% + 1px);
|
|
385
|
+
width: 8px;
|
|
386
|
+
height: 2px;
|
|
387
|
+
background: #ffffff;
|
|
388
|
+
border-radius: 999px;
|
|
389
|
+
transform-origin: center;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
.mb-mindmap-side-btn--down::before {
|
|
393
|
+
transform: translate(-88%, -36%) rotate(35deg);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
.mb-mindmap-side-btn--down::after {
|
|
397
|
+
transform: translate(-12%, -36%) rotate(-35deg);
|
|
398
|
+
}
|
|
399
|
+
|
|
300
400
|
.mb-revit-show-in-model {
|
|
301
401
|
position: absolute;
|
|
302
402
|
transform: translate(-50%, -100%);
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { Events } from '../../core/events/Events.js';
|
|
2
|
+
import { MINDMAP_LAYOUT } from '../mindmap/MindmapLayoutConfig.js';
|
|
3
|
+
import { createRootMindmapIntentMetadata } from '../../mindmap/MindmapCompoundContract.js';
|
|
2
4
|
|
|
3
5
|
export class ToolbarActionRouter {
|
|
4
6
|
constructor(toolbar) {
|
|
@@ -76,6 +78,39 @@ export class ToolbarActionRouter {
|
|
|
76
78
|
return true;
|
|
77
79
|
}
|
|
78
80
|
|
|
81
|
+
if (toolType === 'mindmap-add') {
|
|
82
|
+
const mindmapWidth = MINDMAP_LAYOUT.width;
|
|
83
|
+
const mindmapHeight = MINDMAP_LAYOUT.height;
|
|
84
|
+
this.toolbar.animateButton(button);
|
|
85
|
+
this.toolbar.closeShapesPopup();
|
|
86
|
+
this.toolbar.closeDrawPopup();
|
|
87
|
+
this.toolbar.closeEmojiPopup();
|
|
88
|
+
this.toolbar.eventBus.emit(Events.Keyboard.ToolSelect, { tool: 'place' });
|
|
89
|
+
this.toolbar.placeSelectedButtonId = 'mindmap';
|
|
90
|
+
this.toolbar.setActiveToolbarButton('place');
|
|
91
|
+
this.toolbar.eventBus.emit(Events.Place.Set, {
|
|
92
|
+
type: 'mindmap',
|
|
93
|
+
size: { width: mindmapWidth, height: mindmapHeight },
|
|
94
|
+
properties: {
|
|
95
|
+
mindmap: createRootMindmapIntentMetadata(),
|
|
96
|
+
fontSize: MINDMAP_LAYOUT.fontSize,
|
|
97
|
+
width: mindmapWidth,
|
|
98
|
+
height: mindmapHeight,
|
|
99
|
+
capsuleBaseWidth: mindmapWidth,
|
|
100
|
+
capsuleBaseHeight: mindmapHeight,
|
|
101
|
+
paddingX: MINDMAP_LAYOUT.paddingX,
|
|
102
|
+
paddingY: MINDMAP_LAYOUT.paddingY,
|
|
103
|
+
maxLineChars: MINDMAP_LAYOUT.maxLineChars,
|
|
104
|
+
textColor: 0x212121,
|
|
105
|
+
strokeColor: 0x2563EB,
|
|
106
|
+
fillColor: 0x3B82F6,
|
|
107
|
+
fillAlpha: 0.25,
|
|
108
|
+
strokeWidth: 1
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
|
|
79
114
|
if (toolType === 'frame') {
|
|
80
115
|
this.toolbar.animateButton(button);
|
|
81
116
|
this.toolbar.toggleFramePopup(button);
|
|
@@ -183,8 +183,8 @@ export class ToolbarPopupsController {
|
|
|
183
183
|
const buttonRect = anchorButton.getBoundingClientRect();
|
|
184
184
|
const top = buttonRect.top - toolbarRect.top - 4;
|
|
185
185
|
const left = this.toolbar.element.offsetWidth + 8;
|
|
186
|
-
this.toolbar.shapesPopupEl.style.top = `${top}px`;
|
|
187
|
-
this.toolbar.shapesPopupEl.style.left = `${left}px`;
|
|
186
|
+
this.toolbar.shapesPopupEl.style.top = `${Math.round(top)}px`;
|
|
187
|
+
this.toolbar.shapesPopupEl.style.left = `${Math.round(left)}px`;
|
|
188
188
|
this.toolbar.shapesPopupEl.style.display = 'block';
|
|
189
189
|
}
|
|
190
190
|
|
|
@@ -363,8 +363,8 @@ export class ToolbarPopupsController {
|
|
|
363
363
|
const buttonRect = anchorButton.getBoundingClientRect();
|
|
364
364
|
const top = buttonRect.top - toolbarRect.top - 4;
|
|
365
365
|
const left = this.toolbar.element.offsetWidth + 8;
|
|
366
|
-
this.toolbar.drawPopupEl.style.top = `${top}px`;
|
|
367
|
-
this.toolbar.drawPopupEl.style.left = `${left}px`;
|
|
366
|
+
this.toolbar.drawPopupEl.style.top = `${Math.round(top)}px`;
|
|
367
|
+
this.toolbar.drawPopupEl.style.left = `${Math.round(left)}px`;
|
|
368
368
|
this.toolbar.drawPopupEl.style.display = 'block';
|
|
369
369
|
}
|
|
370
370
|
|
|
@@ -652,8 +652,8 @@ export class ToolbarPopupsController {
|
|
|
652
652
|
const minTop = 8;
|
|
653
653
|
const maxTop = Math.max(minTop, containerHeight - popupHeight - 8);
|
|
654
654
|
const top = Math.min(Math.max(minTop, desiredTop), maxTop);
|
|
655
|
-
this.toolbar.emojiPopupEl.style.top = `${top}px`;
|
|
656
|
-
this.toolbar.emojiPopupEl.style.left = `${left}px`;
|
|
655
|
+
this.toolbar.emojiPopupEl.style.top = `${Math.round(top)}px`;
|
|
656
|
+
this.toolbar.emojiPopupEl.style.left = `${Math.round(left)}px`;
|
|
657
657
|
this.toolbar.emojiPopupEl.style.visibility = 'visible';
|
|
658
658
|
}
|
|
659
659
|
|
|
@@ -25,6 +25,7 @@ export class ToolbarRenderer {
|
|
|
25
25
|
|
|
26
26
|
const existingTools = [
|
|
27
27
|
{ id: 'frame', iconName: 'frame', title: 'Добавить фрейм', type: 'frame' },
|
|
28
|
+
{ id: 'mindmap', iconName: 'mindmap', title: 'Схема', type: 'mindmap-add' },
|
|
28
29
|
{ id: 'divider', type: 'divider' },
|
|
29
30
|
{ id: 'undo', iconName: 'undo', title: 'Отменить (Ctrl+Z)', type: 'undo', disabled: true },
|
|
30
31
|
{ id: 'redo', iconName: 'redo', title: 'Повторить (Ctrl+Y)', type: 'redo', disabled: true }
|
package/src/utils/iconLoader.js
CHANGED
|
@@ -28,14 +28,15 @@ export class IconLoader {
|
|
|
28
28
|
import('../assets/icons/frame.svg?raw'),
|
|
29
29
|
import('../assets/icons/clear.svg?raw'),
|
|
30
30
|
import('../assets/icons/undo.svg?raw'),
|
|
31
|
-
import('../assets/icons/redo.svg?raw')
|
|
31
|
+
import('../assets/icons/redo.svg?raw'),
|
|
32
|
+
import('../assets/icons/mindmap.svg?raw')
|
|
32
33
|
]);
|
|
33
34
|
|
|
34
35
|
// Сохраняем иконки в кэш
|
|
35
36
|
const iconNames = [
|
|
36
37
|
'select', 'pan', 'text-add', 'note', 'image', 'shapes',
|
|
37
38
|
'pencil', 'comments', 'attachments', 'emoji', 'frame',
|
|
38
|
-
'clear', 'undo', 'redo'
|
|
39
|
+
'clear', 'undo', 'redo', 'mindmap'
|
|
39
40
|
];
|
|
40
41
|
|
|
41
42
|
iconNames.forEach((name, index) => {
|
|
@@ -134,6 +135,10 @@ export class IconLoader {
|
|
|
134
135
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
|
135
136
|
<path d="M15 14L20 9L15 4M4 20V13C4 11.9391 4.42143 10.9217 5.17157 10.1716C5.92172 9.42143 6.93913 9 8 9H20"
|
|
136
137
|
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
138
|
+
</svg>`,
|
|
139
|
+
'mindmap': `<?xml version="1.0" encoding="UTF-8"?>
|
|
140
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
|
141
|
+
<path fill="currentColor" fill-rule="evenodd" clip-rule="evenodd" d="M19 2a3 3 0 1 1 0 6c-.463 0-.9-.109-1.291-.296l-1.19 1.19A3.992 3.992 0 0 1 18 12a3.991 3.991 0 0 1-1.48 3.105l1.189 1.19A2.984 2.984 0 0 1 19 16a3 3 0 1 1-3 3c0-.463.108-.9.295-1.291l-1.748-1.748A4.106 4.106 0 0 1 14 16h-4c-.186 0-.37-.014-.549-.04l-1.747 1.75c.187.392.296.828.296 1.291a3 3 0 1 1-3-3c.462 0 .899.108 1.29.295l1.19-1.19A3.992 3.992 0 0 1 6 12a3.99 3.99 0 0 1 1.48-3.106l-1.19-1.19A2.982 2.982 0 0 1 5 8a3 3 0 1 1 3-3c0 .463-.109.899-.296 1.29l1.748 1.748C9.632 8.014 9.814 8 10 8h4c.185 0 .368.013.547.037l1.748-1.747A2.983 2.983 0 0 1 16 5a3 3 0 0 1 3-3ZM5 18a1 1 0 1 0 0 2 1 1 0 0 0 0-2Zm14 0a1 1 0 1 0 0 2 1 1 0 0 0 0-2Zm-9-8a2 2 0 1 0 0 4h4a2 2 0 1 0 0-4h-4ZM5 4a1 1 0 1 0 0 2 1 1 0 0 0 0-2Zm14 0a1 1 0 1 0 0 2 1 1 0 0 0 0-2Z"/>
|
|
137
142
|
</svg>`
|
|
138
143
|
};
|
|
139
144
|
|
|
@@ -187,7 +192,7 @@ export class IconLoader {
|
|
|
187
192
|
const iconNames = [
|
|
188
193
|
'select', 'pan', 'text-add', 'note', 'image', 'shapes',
|
|
189
194
|
'pencil', 'comments', 'attachments', 'emoji', 'frame',
|
|
190
|
-
'clear', 'undo', 'redo'
|
|
195
|
+
'clear', 'undo', 'redo', 'mindmap'
|
|
191
196
|
];
|
|
192
197
|
|
|
193
198
|
iconNames.forEach(name => {
|
|
@@ -219,7 +224,8 @@ export class IconLoader {
|
|
|
219
224
|
'frame': '<svg width="20" height="20" viewBox="0 0 20 20"><rect x="2" y="2" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2"/></svg>',
|
|
220
225
|
'clear': '<svg width="20" height="20" viewBox="0 0 20 20"><path d="M3 6H17L16 18H4L3 6Z" fill="currentColor"/></svg>',
|
|
221
226
|
'undo': '<svg width="20" height="20" viewBox="0 0 20 20"><path d="M8 4L3 9L8 14" stroke="currentColor" stroke-width="2" fill="none"/></svg>',
|
|
222
|
-
'redo': '<svg width="20" height="20" viewBox="0 0 20 20"><path d="M12 4L17 9L12 14" stroke="currentColor" stroke-width="2" fill="none"/></svg>'
|
|
227
|
+
'redo': '<svg width="20" height="20" viewBox="0 0 20 20"><path d="M12 4L17 9L12 14" stroke="currentColor" stroke-width="2" fill="none"/></svg>',
|
|
228
|
+
'mindmap': '<svg width="20" height="20" viewBox="0 0 20 20"><circle cx="4" cy="4" r="2" fill="currentColor"/><circle cx="16" cy="4" r="2" fill="currentColor"/><circle cx="4" cy="16" r="2" fill="currentColor"/><circle cx="16" cy="16" r="2" fill="currentColor"/><rect x="7" y="8" width="6" height="4" rx="2" fill="currentColor"/><path d="M6 5L8 8M14 8L16 5M8 12L6 15M12 12L14 15" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>'
|
|
223
229
|
};
|
|
224
230
|
|
|
225
231
|
return fallbacks[iconName] || fallbacks['select'];
|