From c091f67db334024bd6b4c65d1833b2c60e3e0a45 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 17 Jan 2025 11:15:14 +0000 Subject: [PATCH] Lexical: Added color format custom color select Includes tracking of selected colors via localstorage for display. --- resources/icons/editor/color-select.svg | 1 + .../ui/framework/blocks/color-picker.ts | 49 ++++++++++++++++++- resources/js/wysiwyg/ui/framework/core.ts | 7 +++ 3 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 resources/icons/editor/color-select.svg diff --git a/resources/icons/editor/color-select.svg b/resources/icons/editor/color-select.svg new file mode 100644 index 000000000..cef686655 --- /dev/null +++ b/resources/icons/editor/color-select.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/js/wysiwyg/ui/framework/blocks/color-picker.ts b/resources/js/wysiwyg/ui/framework/blocks/color-picker.ts index b068fb4f0..65623e1b2 100644 --- a/resources/js/wysiwyg/ui/framework/blocks/color-picker.ts +++ b/resources/js/wysiwyg/ui/framework/blocks/color-picker.ts @@ -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) { diff --git a/resources/js/wysiwyg/ui/framework/core.ts b/resources/js/wysiwyg/ui/framework/core.ts index 3433b96e8..90ce4ebf9 100644 --- a/resources/js/wysiwyg/ui/framework/core.ts +++ b/resources/js/wysiwyg/ui/framework/core.ts @@ -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); }