From 13d970c7ce0bf9b88c3553b561cef11cbba0e71a Mon Sep 17 00:00:00 2001 From: Dan Brown <ssddanbrown@googlemail.com> Date: Wed, 19 Jun 2024 20:00:29 +0100 Subject: [PATCH] Lexical: Added button icon system With a bunch of default icons --- dev/build/esbuild.js | 7 +++ resources/icons/editor/align-center.svg | 1 + resources/icons/editor/align-justify.svg | 1 + resources/icons/editor/align-left.svg | 1 + resources/icons/editor/align-right.svg | 1 + resources/icons/editor/bold.svg | 1 + resources/icons/editor/code-block.svg | 1 + resources/icons/editor/code.svg | 1 + resources/icons/editor/details.svg | 1 + resources/icons/editor/format-clear.svg | 1 + resources/icons/editor/help.svg | 1 + resources/icons/editor/horizontal-rule.svg | 1 + resources/icons/editor/image.svg | 1 + resources/icons/editor/indent-decrease.svg | 1 + resources/icons/editor/indent-increase.svg | 1 + resources/icons/editor/italic.svg | 1 + resources/icons/editor/link.svg | 1 + resources/icons/editor/list-bullet.svg | 1 + resources/icons/editor/list-check.svg | 1 + resources/icons/editor/list-numbered.svg | 1 + resources/icons/editor/redo.svg | 1 + resources/icons/editor/source-view.svg | 1 + resources/icons/editor/strikethrough.svg | 1 + resources/icons/editor/subscript.svg | 1 + resources/icons/editor/superscript.svg | 1 + resources/icons/editor/underlined.svg | 1 + resources/icons/editor/undo.svg | 1 + resources/js/global.d.ts | 4 ++ resources/js/wysiwyg/helpers.ts | 6 ++- .../wysiwyg/ui/defaults/button-definitions.ts | 50 ++++++++++++++----- resources/js/wysiwyg/ui/framework/buttons.ts | 12 ++++- resources/js/wysiwyg/ui/toolbars.ts | 1 + resources/sass/_editor.scss | 5 ++ tsconfig.json | 4 +- 34 files changed, 99 insertions(+), 16 deletions(-) create mode 100644 resources/icons/editor/align-center.svg create mode 100644 resources/icons/editor/align-justify.svg create mode 100644 resources/icons/editor/align-left.svg create mode 100644 resources/icons/editor/align-right.svg create mode 100644 resources/icons/editor/bold.svg create mode 100644 resources/icons/editor/code-block.svg create mode 100644 resources/icons/editor/code.svg create mode 100644 resources/icons/editor/details.svg create mode 100644 resources/icons/editor/format-clear.svg create mode 100644 resources/icons/editor/help.svg create mode 100644 resources/icons/editor/horizontal-rule.svg create mode 100644 resources/icons/editor/image.svg create mode 100644 resources/icons/editor/indent-decrease.svg create mode 100644 resources/icons/editor/indent-increase.svg create mode 100644 resources/icons/editor/italic.svg create mode 100644 resources/icons/editor/link.svg create mode 100644 resources/icons/editor/list-bullet.svg create mode 100644 resources/icons/editor/list-check.svg create mode 100644 resources/icons/editor/list-numbered.svg create mode 100644 resources/icons/editor/redo.svg create mode 100644 resources/icons/editor/source-view.svg create mode 100644 resources/icons/editor/strikethrough.svg create mode 100644 resources/icons/editor/subscript.svg create mode 100644 resources/icons/editor/superscript.svg create mode 100644 resources/icons/editor/underlined.svg create mode 100644 resources/icons/editor/undo.svg create mode 100644 resources/js/global.d.ts 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 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M120-120v-80h720v80H120Zm160-160v-80h400v80H280ZM120-440v-80h720v80H120Zm160-160v-80h400v80H280ZM120-760v-80h720v80H120Z"/></svg> \ 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 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M120-120v-80h720v80H120Zm0-160v-80h720v80H120Zm0-160v-80h720v80H120Zm0-160v-80h720v80H120Zm0-160v-80h720v80H120Z"/></svg> \ 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 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M120-120v-80h720v80H120Zm0-160v-80h480v80H120Zm0-160v-80h720v80H120Zm0-160v-80h480v80H120Zm0-160v-80h720v80H120Z"/></svg> \ 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 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M120-760v-80h720v80H120Zm240 160v-80h480v80H360ZM120-440v-80h720v80H120Zm240 160v-80h480v80H360ZM120-120v-80h720v80H120Z"/></svg> \ 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 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M272-200v-560h221q65 0 120 40t55 111q0 51-23 78.5T602-491q25 11 55.5 41t30.5 90q0 89-65 124.5T501-200H272Zm121-112h104q48 0 58.5-24.5T566-372q0-11-10.5-35.5T494-432H393v120Zm0-228h93q33 0 48-17t15-38q0-24-17-39t-44-15h-95v109Z"/></svg> \ 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 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="m384-336 56-57-87-87 87-87-56-57-144 144 144 144Zm192 0 144-144-144-144-56 57 87 87-87 87 56 57ZM200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560H200v560Zm0-560v560-560Z"/></svg> \ 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 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M320-240 80-480l240-240 57 57-184 184 183 183-56 56Zm320 0-57-57 184-184-183-183 56-56 240 240-240 240Z"/></svg> \ 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 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-480H200v480Zm80-280v-80h400v80H280Zm0 160v-80h240v80H280Z"/></svg> \ 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 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="m528-546-93-93-121-121h486v120H568l-40 94ZM792-56 460-388l-80 188H249l119-280L56-792l56-56 736 736-56 56Z"/></svg> \ 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 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M478-240q21 0 35.5-14.5T528-290q0-21-14.5-35.5T478-340q-21 0-35.5 14.5T428-290q0 21 14.5 35.5T478-240Zm-36-154h74q0-33 7.5-52t42.5-52q26-26 41-49.5t15-56.5q0-56-41-86t-97-30q-57 0-92.5 30T342-618l66 26q5-18 22.5-39t53.5-21q32 0 48 17.5t16 38.5q0 20-12 37.5T506-526q-44 39-54 59t-10 73Zm38 314q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z"/></svg> \ 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 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M160-440v-80h640v80H160Z"/></svg> \ 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 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h360v80H200v560h560v-360h80v360q0 33-23.5 56.5T760-120H200Zm480-480v-80h-80v-80h80v-80h80v80h80v80h-80v80h-80ZM240-280h480L570-480 450-320l-90-120-120 160Zm-40-480v560-560Z"/></svg> \ 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 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M120-120v-80h720v80H120Zm320-160v-80h400v80H440Zm0-160v-80h400v80H440Zm0-160v-80h400v80H440ZM120-760v-80h720v80H120Zm160 440L120-480l160-160v320Z"/></svg> \ 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 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M120-120v-80h720v80H120Zm320-160v-80h400v80H440Zm0-160v-80h400v80H440Zm0-160v-80h400v80H440ZM120-760v-80h720v80H120Zm0 440v-320l160 160-160 160Z"/></svg> \ 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 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M200-200v-100h160l120-360H320v-100h400v100H580L460-300h140v100H200Z"/></svg> \ 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 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M680-160v-120H560v-80h120v-120h80v120h120v80H760v120h-80ZM440-280H280q-83 0-141.5-58.5T80-480q0-83 58.5-141.5T280-680h160v80H280q-50 0-85 35t-35 85q0 50 35 85t85 35h160v80ZM320-440v-80h320v80H320Zm560-40h-80q0-50-35-85t-85-35H520v-80h160q83 0 141.5 58.5T880-480Z"/></svg> \ 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 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M360-200v-80h480v80H360Zm0-240v-80h480v80H360Zm0-240v-80h480v80H360ZM200-160q-33 0-56.5-23.5T120-240q0-33 23.5-56.5T200-320q33 0 56.5 23.5T280-240q0 33-23.5 56.5T200-160Zm0-240q-33 0-56.5-23.5T120-480q0-33 23.5-56.5T200-560q33 0 56.5 23.5T280-480q0 33-23.5 56.5T200-400Zm0-240q-33 0-56.5-23.5T120-720q0-33 23.5-56.5T200-800q33 0 56.5 23.5T280-720q0 33-23.5 56.5T200-640Z"/></svg> \ 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 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="#5f6368"><path d="M222-200 80-342l56-56 85 85 170-170 56 57-225 226Zm0-320L80-662l56-56 85 85 170-170 56 57-225 226Zm298 240v-80h360v80H520Zm0-320v-80h360v80H520Z"/></svg> \ 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 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="#5f6368"><path d="M120-80v-60h100v-30h-60v-60h60v-30H120v-60h120q17 0 28.5 11.5T280-280v40q0 17-11.5 28.5T240-200q17 0 28.5 11.5T280-160v40q0 17-11.5 28.5T240-80H120Zm0-280v-110q0-17 11.5-28.5T160-510h60v-30H120v-60h120q17 0 28.5 11.5T280-560v70q0 17-11.5 28.5T240-450h-60v30h100v60H120Zm60-280v-180h-60v-60h120v240h-60Zm180 440v-80h480v80H360Zm0-240v-80h480v80H360Zm0-240v-80h480v80H360Z"/></svg> \ 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 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" ><path d="M396-200q-97 0-166.5-63T160-420q0-94 69.5-157T396-640h252L544-744l56-56 200 200-200 200-56-56 104-104H396q-63 0-109.5 40T240-420q0 60 46.5 100T396-280h284v80H396Z"/></svg> \ 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 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="m384-336 56-58-86-86 86-86-56-58-144 144 144 144Zm192 0 144-144-144-144-56 58 86 86-86 86 56 58ZM200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h168q13-36 43.5-58t68.5-22q38 0 68.5 22t43.5 58h168q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560H200v560Zm280-590q13 0 21.5-8.5T510-820q0-13-8.5-21.5T480-850q-13 0-21.5 8.5T450-820q0 13 8.5 21.5T480-790ZM200-200v-560 560Z"/></svg> \ 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 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M80-400v-80h800v80H80Zm340-160v-120H200v-120h560v120H540v120H420Zm0 400v-160h120v160H420Z"/></svg> \ 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 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M760-160v-80q0-17 11.5-28.5T800-280h80v-40H760v-40h120q17 0 28.5 11.5T920-320v40q0 17-11.5 28.5T880-240h-80v40h120v40H760Zm-525-80 185-291-172-269h106l124 200h4l123-200h107L539-531l186 291H618L482-457h-4L342-240H235Z"/></svg> \ 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 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M760-600v-80q0-17 11.5-28.5T800-720h80v-40H760v-40h120q17 0 28.5 11.5T920-760v40q0 17-11.5 28.5T880-680h-80v40h120v40H760ZM235-160l185-291-172-269h106l124 200h4l123-200h107L539-451l186 291H618L482-377h-4L342-160H235Z"/></svg> \ 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 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M200-120v-80h560v80H200Zm280-160q-101 0-157-63t-56-167v-330h103v336q0 56 28 91t82 35q54 0 82-35t28-91v-336h103v330q0 104-56 167t-157 63Z"/></svg> \ 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 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M280-200v-80h284q63 0 109.5-40T720-420q0-60-46.5-100T564-560H312l104 104-56 56-200-200 200-200 56 56-104 104h252q97 0 166.5 63T800-420q0 94-69.5 157T564-200H280Z"/></svg> \ 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<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) { 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. */