diff --git a/dev/build/esbuild.js b/dev/build/esbuild.js
index 7f180fc07..0680f4ac3 100644
--- a/dev/build/esbuild.js
+++ b/dev/build/esbuild.js
@@ -32,6 +32,13 @@ esbuild.build({
format: 'esm',
minify: isProd,
logLevel: 'info',
+ loader: {
+ '.svg': 'text',
+ },
+ absWorkingDir: path.join(__dirname, '../..'),
+ alias: {
+ '@icons': './resources/icons',
+ },
banner: {
js: '// See the "/licenses" URI for full package license details',
css: '/* See the "/licenses" URI for full package license details */',
diff --git a/resources/icons/editor/align-center.svg b/resources/icons/editor/align-center.svg
new file mode 100644
index 000000000..495ae000c
--- /dev/null
+++ b/resources/icons/editor/align-center.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/icons/editor/align-justify.svg b/resources/icons/editor/align-justify.svg
new file mode 100644
index 000000000..bf8f61abb
--- /dev/null
+++ b/resources/icons/editor/align-justify.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/icons/editor/align-left.svg b/resources/icons/editor/align-left.svg
new file mode 100644
index 000000000..811212755
--- /dev/null
+++ b/resources/icons/editor/align-left.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/icons/editor/align-right.svg b/resources/icons/editor/align-right.svg
new file mode 100644
index 000000000..839110c42
--- /dev/null
+++ b/resources/icons/editor/align-right.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/icons/editor/bold.svg b/resources/icons/editor/bold.svg
new file mode 100644
index 000000000..93cc44a3f
--- /dev/null
+++ b/resources/icons/editor/bold.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/icons/editor/code-block.svg b/resources/icons/editor/code-block.svg
new file mode 100644
index 000000000..308db53b4
--- /dev/null
+++ b/resources/icons/editor/code-block.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/icons/editor/code.svg b/resources/icons/editor/code.svg
new file mode 100644
index 000000000..d8434b761
--- /dev/null
+++ b/resources/icons/editor/code.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/icons/editor/details.svg b/resources/icons/editor/details.svg
new file mode 100644
index 000000000..d86e8c423
--- /dev/null
+++ b/resources/icons/editor/details.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/icons/editor/format-clear.svg b/resources/icons/editor/format-clear.svg
new file mode 100644
index 000000000..b6483fb56
--- /dev/null
+++ b/resources/icons/editor/format-clear.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/icons/editor/help.svg b/resources/icons/editor/help.svg
new file mode 100644
index 000000000..8c3410b84
--- /dev/null
+++ b/resources/icons/editor/help.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/icons/editor/horizontal-rule.svg b/resources/icons/editor/horizontal-rule.svg
new file mode 100644
index 000000000..c70df0d6e
--- /dev/null
+++ b/resources/icons/editor/horizontal-rule.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/icons/editor/image.svg b/resources/icons/editor/image.svg
new file mode 100644
index 000000000..81d04cea7
--- /dev/null
+++ b/resources/icons/editor/image.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/icons/editor/indent-decrease.svg b/resources/icons/editor/indent-decrease.svg
new file mode 100644
index 000000000..af0caa862
--- /dev/null
+++ b/resources/icons/editor/indent-decrease.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/icons/editor/indent-increase.svg b/resources/icons/editor/indent-increase.svg
new file mode 100644
index 000000000..aa6b4cb36
--- /dev/null
+++ b/resources/icons/editor/indent-increase.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/icons/editor/italic.svg b/resources/icons/editor/italic.svg
new file mode 100644
index 000000000..a98819427
--- /dev/null
+++ b/resources/icons/editor/italic.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/icons/editor/link.svg b/resources/icons/editor/link.svg
new file mode 100644
index 000000000..b29800dc3
--- /dev/null
+++ b/resources/icons/editor/link.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/icons/editor/list-bullet.svg b/resources/icons/editor/list-bullet.svg
new file mode 100644
index 000000000..c073c6ff0
--- /dev/null
+++ b/resources/icons/editor/list-bullet.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/icons/editor/list-check.svg b/resources/icons/editor/list-check.svg
new file mode 100644
index 000000000..f30266b27
--- /dev/null
+++ b/resources/icons/editor/list-check.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/icons/editor/list-numbered.svg b/resources/icons/editor/list-numbered.svg
new file mode 100644
index 000000000..92cdbf0ae
--- /dev/null
+++ b/resources/icons/editor/list-numbered.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/icons/editor/redo.svg b/resources/icons/editor/redo.svg
new file mode 100644
index 000000000..d542296c5
--- /dev/null
+++ b/resources/icons/editor/redo.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/icons/editor/source-view.svg b/resources/icons/editor/source-view.svg
new file mode 100644
index 000000000..5314c39da
--- /dev/null
+++ b/resources/icons/editor/source-view.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/icons/editor/strikethrough.svg b/resources/icons/editor/strikethrough.svg
new file mode 100644
index 000000000..92d14aa76
--- /dev/null
+++ b/resources/icons/editor/strikethrough.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/icons/editor/subscript.svg b/resources/icons/editor/subscript.svg
new file mode 100644
index 000000000..e877b3359
--- /dev/null
+++ b/resources/icons/editor/subscript.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/icons/editor/superscript.svg b/resources/icons/editor/superscript.svg
new file mode 100644
index 000000000..897ceddc2
--- /dev/null
+++ b/resources/icons/editor/superscript.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/icons/editor/underlined.svg b/resources/icons/editor/underlined.svg
new file mode 100644
index 000000000..5d17ef6ef
--- /dev/null
+++ b/resources/icons/editor/underlined.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/icons/editor/undo.svg b/resources/icons/editor/undo.svg
new file mode 100644
index 000000000..4b9f22675
--- /dev/null
+++ b/resources/icons/editor/undo.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/js/global.d.ts b/resources/js/global.d.ts
new file mode 100644
index 000000000..c5aba8ee2
--- /dev/null
+++ b/resources/js/global.d.ts
@@ -0,0 +1,4 @@
+declare module '*.svg' {
+ const content: string;
+ export default content;
+}
\ No newline at end of file
diff --git a/resources/js/wysiwyg/helpers.ts b/resources/js/wysiwyg/helpers.ts
index 40379cc27..d7cd23a35 100644
--- a/resources/js/wysiwyg/helpers.ts
+++ b/resources/js/wysiwyg/helpers.ts
@@ -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 = {}, children: (string|HTMLElement)[] = []): HTMLElement {
+export function el(tag: string, attrs: Record = {}, 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) {
diff --git a/resources/js/wysiwyg/ui/defaults/button-definitions.ts b/resources/js/wysiwyg/ui/defaults/button-definitions.ts
index 57460ef60..7fa1fb5f8 100644
--- a/resources/js/wysiwyg/ui/defaults/button-definitions.ts
+++ b/resources/js/wysiwyg/ui/defaults/button-definitions.ts
@@ -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);
diff --git a/resources/js/wysiwyg/ui/framework/buttons.ts b/resources/js/wysiwyg/ui/framework/buttons.ts
index c3ba533b3..332b35099 100644
--- a/resources/js/wysiwyg/ui/framework/buttons.ts
+++ b/resources/js/wysiwyg/ui/framework/buttons.ts
@@ -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));
diff --git a/resources/js/wysiwyg/ui/toolbars.ts b/resources/js/wysiwyg/ui/toolbars.ts
index fe19b94ed..559e9a87c 100644
--- a/resources/js/wysiwyg/ui/toolbars.ts
+++ b/resources/js/wysiwyg/ui/toolbars.ts
@@ -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', [
diff --git a/resources/sass/_editor.scss b/resources/sass/_editor.scss
index 13d8e96f9..f8c895afd 100644
--- a/resources/sass/_editor.scss
+++ b/resources/sass/_editor.scss
@@ -29,6 +29,11 @@
padding: 4px 6px;
display: block;
}
+.editor-button-icon svg {
+ width: 24px;
+ height: 24px;
+ fill: #000;
+}
// Containers
.editor-dropdown-menu-container {
diff --git a/tsconfig.json b/tsconfig.json
index e075f973c..40d930149 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -29,7 +29,9 @@
// "rootDir": "./", /* Specify the root folder within your source files. */
// "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
- // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
+ "paths": { /* Specify a set of entries that re-map imports to additional lookup locations. */
+ "@icons/*": ["./resources/icons/*"]
+ },
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
// "types": [], /* Specify type package names to be included without being referenced in a source file. */