mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-08-07 23:03:00 +03:00
Lexical: Added color format custom color select
Includes tracking of selected colors via localstorage for display.
This commit is contained in:
@@ -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) {
|
||||
|
@@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user