mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-03-13 22:11:24 +08:00
Lexical: Added color format custom color select
Includes tracking of selected colors via localstorage for display.
This commit is contained in:
parent
7f5fd16dc6
commit
c091f67db3
1
resources/icons/editor/color-select.svg
Normal file
1
resources/icons/editor/color-select.svg
Normal file
@ -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>
|
After Width: | Height: | Size: 808 B |
@ -4,6 +4,8 @@ import {$patchStyleText} from "@lexical/selection";
|
|||||||
import {el} from "../../../utils/dom";
|
import {el} from "../../../utils/dom";
|
||||||
|
|
||||||
import removeIcon from "@icons/editor/color-clear.svg";
|
import removeIcon from "@icons/editor/color-clear.svg";
|
||||||
|
import selectIcon from "@icons/editor/color-select.svg";
|
||||||
|
import {uniqueIdSmall} from "../../../../services/util";
|
||||||
|
|
||||||
const colorChoices = [
|
const colorChoices = [
|
||||||
'#000000',
|
'#000000',
|
||||||
@ -34,6 +36,8 @@ const colorChoices = [
|
|||||||
'#34495E',
|
'#34495E',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const storageKey = 'bs-lexical-custom-colors';
|
||||||
|
|
||||||
export class EditorColorPicker extends EditorUiElement {
|
export class EditorColorPicker extends EditorUiElement {
|
||||||
|
|
||||||
protected styleProperty: string;
|
protected styleProperty: string;
|
||||||
@ -44,8 +48,10 @@ export class EditorColorPicker extends EditorUiElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
buildDOM(): HTMLElement {
|
buildDOM(): HTMLElement {
|
||||||
|
const id = uniqueIdSmall();
|
||||||
|
|
||||||
const colorOptions = colorChoices.map(choice => {
|
const allChoices = [...colorChoices, ...this.getCustomColorChoices()];
|
||||||
|
const colorOptions = allChoices.map(choice => {
|
||||||
return el('div', {
|
return el('div', {
|
||||||
class: 'editor-color-select-option',
|
class: 'editor-color-select-option',
|
||||||
style: `background-color: ${choice}`,
|
style: `background-color: ${choice}`,
|
||||||
@ -62,6 +68,25 @@ export class EditorColorPicker extends EditorUiElement {
|
|||||||
removeButton.innerHTML = removeIcon;
|
removeButton.innerHTML = removeIcon;
|
||||||
colorOptions.push(removeButton);
|
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 = [];
|
const colorRows = [];
|
||||||
for (let i = 0; i < colorOptions.length; i+=5) {
|
for (let i = 0; i < colorOptions.length; i+=5) {
|
||||||
const options = colorOptions.slice(i, i + 5);
|
const options = colorOptions.slice(i, i + 5);
|
||||||
@ -79,11 +104,33 @@ export class EditorColorPicker extends EditorUiElement {
|
|||||||
return wrapper;
|
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) {
|
onClick(event: MouseEvent) {
|
||||||
const colorEl = (event.target as HTMLElement).closest('[data-color]') as HTMLElement;
|
const colorEl = (event.target as HTMLElement).closest('[data-color]') as HTMLElement;
|
||||||
if (!colorEl) return;
|
if (!colorEl) return;
|
||||||
|
|
||||||
const color = colorEl.dataset.color as string;
|
const color = colorEl.dataset.color as string;
|
||||||
|
this.setColor(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
setColor(color: string) {
|
||||||
this.getContext().editor.update(() => {
|
this.getContext().editor.update(() => {
|
||||||
const selection = $getSelection();
|
const selection = $getSelection();
|
||||||
if (selection) {
|
if (selection) {
|
||||||
|
@ -53,6 +53,13 @@ export abstract class EditorUiElement {
|
|||||||
return this.dom;
|
return this.dom;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rebuildDOM(): HTMLElement {
|
||||||
|
const newDOM = this.buildDOM();
|
||||||
|
this.dom?.replaceWith(newDOM);
|
||||||
|
this.dom = newDOM;
|
||||||
|
return this.dom;
|
||||||
|
}
|
||||||
|
|
||||||
trans(text: string) {
|
trans(text: string) {
|
||||||
return this.getContext().translate(text);
|
return this.getContext().translate(text);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user