mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-07-31 15:24:31 +03:00
Lexical: Added button icon system
With a bunch of default icons
This commit is contained in:
4
resources/js/global.d.ts
vendored
Normal file
4
resources/js/global.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
declare module '*.svg' {
|
||||
const content: string;
|
||||
export default content;
|
||||
}
|
@ -9,11 +9,13 @@ import {LexicalElementNodeCreator, LexicalNodeMatcher} from "./nodes";
|
||||
import {$getNearestBlockElementAncestorOrThrow} from "@lexical/utils";
|
||||
import {$setBlocksType} from "@lexical/selection";
|
||||
|
||||
export function el(tag: string, attrs: Record<string, string> = {}, children: (string|HTMLElement)[] = []): HTMLElement {
|
||||
export function el(tag: string, attrs: Record<string, string|null> = {}, children: (string|HTMLElement)[] = []): HTMLElement {
|
||||
const el = document.createElement(tag);
|
||||
const attrKeys = Object.keys(attrs);
|
||||
for (const attr of attrKeys) {
|
||||
el.setAttribute(attr, attrs[attr]);
|
||||
if (attrs[attr] !== null) {
|
||||
el.setAttribute(attr, attrs[attr] as string);
|
||||
}
|
||||
}
|
||||
|
||||
for (const child of children) {
|
||||
|
@ -29,9 +29,27 @@ import {$isImageNode, ImageNode} from "../../nodes/image";
|
||||
import {$createDetailsNode, $isDetailsNode} from "../../nodes/details";
|
||||
import {getEditorContentAsHtml} from "../../actions";
|
||||
import {$isListNode, insertList, ListNode, ListType, removeList} from "@lexical/list";
|
||||
import undoIcon from "@icons/editor/undo.svg"
|
||||
import redoIcon from "@icons/editor/redo.svg"
|
||||
import boldIcon from "@icons/editor/bold.svg"
|
||||
import italicIcon from "@icons/editor/italic.svg"
|
||||
import underlinedIcon from "@icons/editor/underlined.svg"
|
||||
import strikethroughIcon from "@icons/editor/strikethrough.svg"
|
||||
import superscriptIcon from "@icons/editor/superscript.svg"
|
||||
import subscriptIcon from "@icons/editor/subscript.svg"
|
||||
import codeIcon from "@icons/editor/code.svg"
|
||||
import formatClearIcon from "@icons/editor/format-clear.svg"
|
||||
import listBulletIcon from "@icons/editor/list-bullet.svg"
|
||||
import listNumberedIcon from "@icons/editor/list-numbered.svg"
|
||||
import listCheckIcon from "@icons/editor/list-check.svg"
|
||||
import linkIcon from "@icons/editor/link.svg"
|
||||
import imageIcon from "@icons/editor/image.svg"
|
||||
import detailsIcon from "@icons/editor/details.svg"
|
||||
import sourceIcon from "@icons/editor/source-view.svg"
|
||||
|
||||
export const undo: EditorButtonDefinition = {
|
||||
label: 'Undo',
|
||||
icon: undoIcon,
|
||||
action(context: EditorUiContext) {
|
||||
context.editor.dispatchCommand(UNDO_COMMAND, undefined);
|
||||
},
|
||||
@ -42,6 +60,7 @@ export const undo: EditorButtonDefinition = {
|
||||
|
||||
export const redo: EditorButtonDefinition = {
|
||||
label: 'Redo',
|
||||
icon: redoIcon,
|
||||
action(context: EditorUiContext) {
|
||||
context.editor.dispatchCommand(REDO_COMMAND, undefined);
|
||||
},
|
||||
@ -116,9 +135,10 @@ export const paragraph: EditorButtonDefinition = {
|
||||
}
|
||||
}
|
||||
|
||||
function buildFormatButton(label: string, format: TextFormatType): EditorButtonDefinition {
|
||||
function buildFormatButton(label: string, format: TextFormatType, icon: string): EditorButtonDefinition {
|
||||
return {
|
||||
label: label,
|
||||
icon,
|
||||
action(context: EditorUiContext) {
|
||||
context.editor.dispatchCommand(FORMAT_TEXT_COMMAND, format);
|
||||
},
|
||||
@ -128,18 +148,19 @@ function buildFormatButton(label: string, format: TextFormatType): EditorButtonD
|
||||
};
|
||||
}
|
||||
|
||||
export const bold: EditorButtonDefinition = buildFormatButton('Bold', 'bold');
|
||||
export const italic: EditorButtonDefinition = buildFormatButton('Italic', 'italic');
|
||||
export const underline: EditorButtonDefinition = buildFormatButton('Underline', 'underline');
|
||||
export const bold: EditorButtonDefinition = buildFormatButton('Bold', 'bold', boldIcon);
|
||||
export const italic: EditorButtonDefinition = buildFormatButton('Italic', 'italic', italicIcon);
|
||||
export const underline: EditorButtonDefinition = buildFormatButton('Underline', 'underline', underlinedIcon);
|
||||
export const textColor: EditorBasicButtonDefinition = {label: 'Text color'};
|
||||
export const highlightColor: EditorBasicButtonDefinition = {label: 'Highlight color'};
|
||||
|
||||
export const strikethrough: EditorButtonDefinition = buildFormatButton('Strikethrough', 'strikethrough');
|
||||
export const superscript: EditorButtonDefinition = buildFormatButton('Superscript', 'superscript');
|
||||
export const subscript: EditorButtonDefinition = buildFormatButton('Subscript', 'subscript');
|
||||
export const code: EditorButtonDefinition = buildFormatButton('Inline Code', 'code');
|
||||
export const strikethrough: EditorButtonDefinition = buildFormatButton('Strikethrough', 'strikethrough', strikethroughIcon);
|
||||
export const superscript: EditorButtonDefinition = buildFormatButton('Superscript', 'superscript', superscriptIcon);
|
||||
export const subscript: EditorButtonDefinition = buildFormatButton('Subscript', 'subscript', subscriptIcon);
|
||||
export const code: EditorButtonDefinition = buildFormatButton('Inline Code', 'code', codeIcon);
|
||||
export const clearFormating: EditorButtonDefinition = {
|
||||
label: 'Clear formatting',
|
||||
icon: formatClearIcon,
|
||||
action(context: EditorUiContext) {
|
||||
context.editor.update(() => {
|
||||
const selection = $getSelection();
|
||||
@ -155,9 +176,10 @@ export const clearFormating: EditorButtonDefinition = {
|
||||
}
|
||||
};
|
||||
|
||||
function buildListButton(label: string, type: ListType): EditorButtonDefinition {
|
||||
function buildListButton(label: string, type: ListType, icon: string): EditorButtonDefinition {
|
||||
return {
|
||||
label,
|
||||
icon,
|
||||
action(context: EditorUiContext) {
|
||||
context.editor.getEditorState().read(() => {
|
||||
const selection = $getSelection();
|
||||
@ -176,13 +198,14 @@ function buildListButton(label: string, type: ListType): EditorButtonDefinition
|
||||
};
|
||||
}
|
||||
|
||||
export const bulletList: EditorButtonDefinition = buildListButton('Bullet list', 'bullet');
|
||||
export const numberList: EditorButtonDefinition = buildListButton('Numbered list', 'number');
|
||||
export const taskList: EditorButtonDefinition = buildListButton('Task list', 'check');
|
||||
export const bulletList: EditorButtonDefinition = buildListButton('Bullet list', 'bullet', listBulletIcon);
|
||||
export const numberList: EditorButtonDefinition = buildListButton('Numbered list', 'number', listNumberedIcon);
|
||||
export const taskList: EditorButtonDefinition = buildListButton('Task list', 'check', listCheckIcon);
|
||||
|
||||
|
||||
export const link: EditorButtonDefinition = {
|
||||
label: 'Insert/edit link',
|
||||
icon: linkIcon,
|
||||
action(context: EditorUiContext) {
|
||||
const linkModal = context.manager.createModal('link');
|
||||
context.editor.getEditorState().read(() => {
|
||||
@ -215,6 +238,7 @@ export const link: EditorButtonDefinition = {
|
||||
|
||||
export const image: EditorButtonDefinition = {
|
||||
label: 'Insert/Edit Image',
|
||||
icon: imageIcon,
|
||||
action(context: EditorUiContext) {
|
||||
const imageModal = context.manager.createModal('image');
|
||||
const selection = context.lastSelection;
|
||||
@ -247,6 +271,7 @@ export const image: EditorButtonDefinition = {
|
||||
|
||||
export const details: EditorButtonDefinition = {
|
||||
label: 'Insert collapsible block',
|
||||
icon: detailsIcon,
|
||||
action(context: EditorUiContext) {
|
||||
context.editor.update(() => {
|
||||
const selection = $getSelection();
|
||||
@ -274,6 +299,7 @@ export const details: EditorButtonDefinition = {
|
||||
|
||||
export const source: EditorButtonDefinition = {
|
||||
label: 'Source code',
|
||||
icon: sourceIcon,
|
||||
async action(context: EditorUiContext) {
|
||||
const modal = context.manager.createModal('source');
|
||||
const source = await getEditorContentAsHtml(context.editor);
|
||||
|
@ -4,6 +4,7 @@ import {el} from "../../helpers";
|
||||
|
||||
export interface EditorBasicButtonDefinition {
|
||||
label: string;
|
||||
icon?: string|undefined;
|
||||
}
|
||||
|
||||
export interface EditorButtonDefinition extends EditorBasicButtonDefinition {
|
||||
@ -21,10 +22,19 @@ export class EditorButton extends EditorUiElement {
|
||||
}
|
||||
|
||||
protected buildDOM(): HTMLButtonElement {
|
||||
|
||||
const label = this.getLabel();
|
||||
let child: string|HTMLElement = label;
|
||||
if (this.definition.icon) {
|
||||
child = el('span', {class: 'editor-button-icon'});
|
||||
child.innerHTML = this.definition.icon;
|
||||
}
|
||||
|
||||
const button = el('button', {
|
||||
type: 'button',
|
||||
class: 'editor-button',
|
||||
}, [this.getLabel()]) as HTMLButtonElement;
|
||||
title: this.definition.icon ? label : null,
|
||||
}, [child]) as HTMLButtonElement;
|
||||
|
||||
button.addEventListener('click', this.onClick.bind(this));
|
||||
|
||||
|
@ -16,6 +16,7 @@ import {FormatPreviewButton} from "./framework/blocks/format-preview-button";
|
||||
import {EditorDropdownButton} from "./framework/blocks/dropdown-button";
|
||||
import {EditorColorPicker} from "./framework/blocks/color-picker";
|
||||
|
||||
console.log(undo);
|
||||
|
||||
export function getMainEditorFullToolbar(): EditorContainerUiElement {
|
||||
return new EditorSimpleClassContainer('editor-toolbar-main', [
|
||||
|
Reference in New Issue
Block a user