mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-11-22 19:02:31 +01:00
Lexical: Integrated diagram manager, added menu split button
This commit is contained in:
parent
ad6b26ba97
commit
0039f893cc
1
resources/icons/caret-down-large.svg
Normal file
1
resources/icons/caret-down-large.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m2 6.9159 10 10.168 10-10.168z" stroke-width="2.0168"/></svg>
|
After Width: | Height: | Size: 131 B |
@ -10,7 +10,6 @@
|
||||
- Alignments: Handle inline block content (image, video)
|
||||
- Image paste upload
|
||||
- Keyboard shortcuts support
|
||||
- Drawing gallery integration
|
||||
- Support media src conversions (https://github.com/tinymce/tinymce/blob/release/6.6/modules/tinymce/src/plugins/media/main/ts/core/UrlPatterns.ts)
|
||||
- Media resize support (like images)
|
||||
- Table caption text support
|
||||
|
@ -30,7 +30,7 @@ import {
|
||||
$insertNewBlockNodeAtSelection,
|
||||
$selectionContainsNodeType
|
||||
} from "../../../utils/selection";
|
||||
import {$isDiagramNode, $openDrawingEditorForNode} from "../../../utils/diagrams";
|
||||
import {$isDiagramNode, $openDrawingEditorForNode, showDiagramManagerForInsert} from "../../../utils/diagrams";
|
||||
import {$createLinkedImageNodeFromImageData, showImageManager} from "../../../utils/images";
|
||||
import {$showImageForm} from "../forms/objects";
|
||||
|
||||
@ -184,6 +184,16 @@ export const diagram: EditorButtonDefinition = {
|
||||
}
|
||||
};
|
||||
|
||||
export const diagramManager: EditorButtonDefinition = {
|
||||
label: 'Drawing manager',
|
||||
action(context: EditorUiContext) {
|
||||
showDiagramManagerForInsert(context);
|
||||
},
|
||||
isActive(): boolean {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export const media: EditorButtonDefinition = {
|
||||
label: 'Insert/edit Media',
|
||||
icon: mediaIcon,
|
||||
|
31
resources/js/wysiwyg/ui/framework/blocks/button-with-menu.ts
Normal file
31
resources/js/wysiwyg/ui/framework/blocks/button-with-menu.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import {EditorContainerUiElement, EditorUiElement} from "../core";
|
||||
import {el} from "../../../utils/dom";
|
||||
import {EditorButton} from "../buttons";
|
||||
import {EditorDropdownButton} from "./dropdown-button";
|
||||
import caretDownIcon from "@icons/caret-down-large.svg";
|
||||
|
||||
export class EditorButtonWithMenu extends EditorContainerUiElement {
|
||||
protected button: EditorButton;
|
||||
protected dropdownButton: EditorDropdownButton;
|
||||
|
||||
constructor(button: EditorButton, menuItems: EditorUiElement[]) {
|
||||
super([button]);
|
||||
|
||||
this.button = button;
|
||||
this.dropdownButton = new EditorDropdownButton({
|
||||
button: {label: 'Menu', icon: caretDownIcon},
|
||||
showOnHover: false,
|
||||
direction: 'vertical',
|
||||
}, menuItems);
|
||||
this.addChildren(this.dropdownButton);
|
||||
}
|
||||
|
||||
buildDOM(): HTMLElement {
|
||||
return el('div', {
|
||||
class: 'editor-button-with-menu-container',
|
||||
}, [
|
||||
this.button.getDOMElement(),
|
||||
this.dropdownButton.getDOMElement()
|
||||
]);
|
||||
}
|
||||
}
|
@ -56,16 +56,15 @@ import {bulletList, numberList, taskList} from "./defaults/buttons/lists";
|
||||
import {
|
||||
codeBlock,
|
||||
details,
|
||||
diagram,
|
||||
diagram, diagramManager,
|
||||
editCodeBlock,
|
||||
horizontalRule,
|
||||
image,
|
||||
link, media,
|
||||
unlink
|
||||
} from "./defaults/buttons/objects";
|
||||
import {$isTableNode} from "@lexical/table";
|
||||
import {$selectionContainsNodeType} from "../utils/selection";
|
||||
import {el} from "../utils/dom";
|
||||
import {EditorButtonWithMenu} from "./framework/blocks/button-with-menu";
|
||||
|
||||
export function getMainEditorFullToolbar(): EditorContainerUiElement {
|
||||
return new EditorSimpleClassContainer('editor-toolbar-main', [
|
||||
@ -166,7 +165,10 @@ export function getMainEditorFullToolbar(): EditorContainerUiElement {
|
||||
new EditorButton(image),
|
||||
new EditorButton(horizontalRule),
|
||||
new EditorButton(codeBlock),
|
||||
new EditorButton(diagram),
|
||||
new EditorButtonWithMenu(
|
||||
new EditorButton(diagram),
|
||||
[new EditorButton(diagramManager)],
|
||||
),
|
||||
new EditorButton(media),
|
||||
new EditorButton(details),
|
||||
]),
|
||||
|
@ -1,8 +1,11 @@
|
||||
import {LexicalEditor, LexicalNode} from "lexical";
|
||||
import {$getSelection, $insertNodes, LexicalEditor, LexicalNode} from "lexical";
|
||||
import {HttpError} from "../../services/http";
|
||||
import {EditorUiContext} from "../ui/framework/core";
|
||||
import * as DrawIO from "../../services/drawio";
|
||||
import {DiagramNode} from "../nodes/diagram";
|
||||
import {$createDiagramNode, DiagramNode} from "../nodes/diagram";
|
||||
import {ImageManager} from "../../components";
|
||||
import {EditorImageData} from "./images";
|
||||
import {$getNodeFromSelection} from "./selection";
|
||||
|
||||
export function $isDiagramNode(node: LexicalNode | null | undefined): node is DiagramNode {
|
||||
return node instanceof DiagramNode;
|
||||
@ -67,4 +70,26 @@ export function $openDrawingEditorForNode(context: EditorUiContext, node: Diagra
|
||||
}, async (pngData: string) => {
|
||||
return updateDrawingNodeFromData(context, node, pngData, isNew);
|
||||
});
|
||||
}
|
||||
|
||||
export function showDiagramManager(callback: (image: EditorImageData) => any) {
|
||||
const imageManager: ImageManager = window.$components.first('image-manager') as ImageManager;
|
||||
imageManager.show((image: EditorImageData) => {
|
||||
callback(image);
|
||||
}, 'drawio');
|
||||
}
|
||||
|
||||
export function showDiagramManagerForInsert(context: EditorUiContext) {
|
||||
const selection = context.lastSelection;
|
||||
showDiagramManager((image: EditorImageData) => {
|
||||
context.editor.update(() => {
|
||||
const diagramNode = $createDiagramNode(image.id, image.url);
|
||||
const selectedDiagram = $getNodeFromSelection(selection, $isDiagramNode);
|
||||
if ($isDiagramNode(selectedDiagram)) {
|
||||
selectedDiagram.replace(diagramNode);
|
||||
} else {
|
||||
$insertNodes([diagramNode]);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
@ -2,7 +2,8 @@ import {ImageManager} from "../../components";
|
||||
import {$createImageNode} from "../nodes/image";
|
||||
import {$createLinkNode, LinkNode} from "@lexical/link";
|
||||
|
||||
type EditorImageData = {
|
||||
export type EditorImageData = {
|
||||
id: string;
|
||||
url: string;
|
||||
thumbs?: {display: string};
|
||||
name: string;
|
||||
|
@ -82,6 +82,31 @@ body.editor-is-fullscreen {
|
||||
fill: currentColor;
|
||||
display: block;
|
||||
}
|
||||
.editor-button-with-menu-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 0;
|
||||
align-items: stretch;
|
||||
border-radius: 4px;
|
||||
.editor-dropdown-menu-container {
|
||||
display: flex;
|
||||
}
|
||||
.editor-dropdown-menu-container > .editor-dropdown-menu {
|
||||
top: 100%;
|
||||
}
|
||||
.editor-dropdown-menu-container > .editor-button {
|
||||
padding-inline: 4px;
|
||||
margin-inline-start: -3px;
|
||||
svg {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
outline: 1px solid #DDD;
|
||||
outline-offset: -3px;
|
||||
}
|
||||
}
|
||||
|
||||
// Containers
|
||||
.editor-dropdown-menu-container {
|
||||
|
Loading…
Reference in New Issue
Block a user