]> BookStack Code Mirror - bookstack/commitdiff
Lexical: Added color format custom color select
authorDan Brown <redacted>
Fri, 17 Jan 2025 11:15:14 +0000 (11:15 +0000)
committerDan Brown <redacted>
Fri, 17 Jan 2025 11:17:51 +0000 (11:17 +0000)
Includes tracking of selected colors via localstorage for display.

resources/icons/editor/color-select.svg [new file with mode: 0644]
resources/js/wysiwyg/ui/framework/blocks/color-picker.ts
resources/js/wysiwyg/ui/framework/core.ts

diff --git a/resources/icons/editor/color-select.svg b/resources/icons/editor/color-select.svg
new file mode 100644 (file)
index 0000000..cef6866
--- /dev/null
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M480-80q-82 0-155-31.5t-127.5-86Q143-252 111.5-325T80-480q0-83 32.5-156t88-127Q256-817 330-848.5T488-880q80 0 151 27.5t124.5 76q53.5 48.5 85 115T880-518q0 115-70 176.5T640-280h-74q-9 0-12.5 5t-3.5 11q0 12 15 34.5t15 51.5q0 50-27.5 74T480-80Zm0-400Zm-220 40q26 0 43-17t17-43q0-26-17-43t-43-17q-26 0-43 17t-17 43q0 26 17 43t43 17Zm120-160q26 0 43-17t17-43q0-26-17-43t-43-17q-26 0-43 17t-17 43q0 26 17 43t43 17Zm200 0q26 0 43-17t17-43q0-26-17-43t-43-17q-26 0-43 17t-17 43q0 26 17 43t43 17Zm120 160q26 0 43-17t17-43q0-26-17-43t-43-17q-26 0-43 17t-17 43q0 26 17 43t43 17ZM480-160q9 0 14.5-5t5.5-13q0-14-15-33t-15-57q0-42 29-67t71-25h70q66 0 113-38.5T800-518q0-121-92.5-201.5T488-800q-136 0-232 93t-96 227q0 133 93.5 226.5T480-160Z"/></svg>
\ No newline at end of file
index b068fb4f0bf323e7f5f91890bd95f61b07f1fb7d..65623e1b21ded8caf1e02a96aaa56a00d57185fb 100644 (file)
@@ -4,6 +4,8 @@ import {$patchStyleText} from "@lexical/selection";
 import {el} from "../../../utils/dom";
 
 import removeIcon from "@icons/editor/color-clear.svg";
+import selectIcon from "@icons/editor/color-select.svg";
+import {uniqueIdSmall} from "../../../../services/util";
 
 const colorChoices = [
     '#000000',
@@ -34,6 +36,8 @@ const colorChoices = [
     '#34495E',
 ];
 
+const storageKey = 'bs-lexical-custom-colors';
+
 export class EditorColorPicker extends EditorUiElement {
 
     protected styleProperty: string;
@@ -44,8 +48,10 @@ export class EditorColorPicker extends EditorUiElement {
     }
 
     buildDOM(): HTMLElement {
+        const id = uniqueIdSmall();
 
-        const colorOptions = colorChoices.map(choice => {
+        const allChoices = [...colorChoices, ...this.getCustomColorChoices()];
+        const colorOptions = allChoices.map(choice => {
             return el('div', {
                 class: 'editor-color-select-option',
                 style: `background-color: ${choice}`,
@@ -62,6 +68,25 @@ export class EditorColorPicker extends EditorUiElement {
         removeButton.innerHTML = removeIcon;
         colorOptions.push(removeButton);
 
+        const selectButton = el('label', {
+            class: 'editor-color-select-option',
+            for: `color-select-${id}`,
+            'data-color': '',
+            title: 'Custom color',
+        }, []);
+        selectButton.innerHTML = selectIcon;
+        colorOptions.push(selectButton);
+
+        const input = el('input', {type: 'color', hidden: 'true', id: `color-select-${id}`}) as HTMLInputElement;
+        colorOptions.push(input);
+        input.addEventListener('change', e => {
+            if (input.value) {
+                this.storeCustomColorChoice(input.value);
+                this.setColor(input.value);
+                this.rebuildDOM();
+            }
+        });
+
         const colorRows = [];
         for (let i = 0; i < colorOptions.length; i+=5) {
             const options = colorOptions.slice(i, i + 5);
@@ -79,11 +104,33 @@ export class EditorColorPicker extends EditorUiElement {
         return wrapper;
     }
 
+    storeCustomColorChoice(color: string) {
+        if (colorChoices.includes(color)) {
+            return;
+        }
+
+        const customColors: string[] = this.getCustomColorChoices();
+        if (customColors.includes(color)) {
+            return;
+        }
+
+        customColors.push(color);
+        window.localStorage.setItem(storageKey, JSON.stringify(customColors));
+    }
+
+    getCustomColorChoices(): string[] {
+        return JSON.parse(window.localStorage.getItem(storageKey) || '[]');
+    }
+
     onClick(event: MouseEvent) {
         const colorEl = (event.target as HTMLElement).closest('[data-color]') as HTMLElement;
         if (!colorEl) return;
 
         const color = colorEl.dataset.color as string;
+        this.setColor(color);
+    }
+
+    setColor(color: string) {
         this.getContext().editor.update(() => {
             const selection = $getSelection();
             if (selection) {
index 3433b96e8d7247076631ac05687e25cb2072450f..90ce4ebf93cb4fc8a1ad44497206370c279b8b6f 100644 (file)
@@ -53,6 +53,13 @@ export abstract class EditorUiElement {
         return this.dom;
     }
 
+    rebuildDOM(): HTMLElement {
+        const newDOM = this.buildDOM();
+        this.dom?.replaceWith(newDOM);
+        this.dom = newDOM;
+        return this.dom;
+    }
+
     trans(text: string) {
         return this.getContext().translate(text);
     }
Morty Proxy This is a proxified and sanitized view of the page, visit original site.