diff --git a/resources/js/wysiwyg/ui/framework/buttons.ts b/resources/js/wysiwyg/ui/framework/buttons.ts index 51c7d294d..2a6f5a976 100644 --- a/resources/js/wysiwyg/ui/framework/buttons.ts +++ b/resources/js/wysiwyg/ui/framework/buttons.ts @@ -19,22 +19,70 @@ export class EditorButton extends EditorUiElement { protected buildDOM(): HTMLButtonElement { const button = el('button', { type: 'button', - class: 'editor-toolbar-button', + class: 'editor-button', }, [this.definition.label]) as HTMLButtonElement; - button.addEventListener('click', event => { - this.definition.action(this.getContext().editor); - }); + button.addEventListener('click', this.onClick.bind(this)); return button; } + protected onClick() { + this.definition.action(this.getContext().editor); + } + updateActiveState(selection: BaseSelection|null) { const isActive = this.definition.isActive(selection); - this.dom?.classList.toggle('editor-toolbar-button-active', isActive); + this.dom?.classList.toggle('editor-button-active', isActive); } updateState(state: EditorUiStateUpdate): void { this.updateActiveState(state.selection); } +} + +export class FormatPreviewButton extends EditorButton { + protected previewSampleElement: HTMLElement; + + constructor(previewSampleElement: HTMLElement,definition: EditorButtonDefinition) { + super(definition); + this.previewSampleElement = previewSampleElement; + } + + protected buildDOM(): HTMLButtonElement { + const button = super.buildDOM(); + button.innerHTML = ''; + + const preview = el('span', { + class: 'editor-button-format-preview' + }, [this.definition.label]); + + const stylesToApply = this.getStylesFromPreview(); + console.log(stylesToApply); + for (const style of Object.keys(stylesToApply)) { + preview.style.setProperty(style, stylesToApply[style]); + } + + button.append(preview); + return button; + } + + protected getStylesFromPreview(): Record { + const wrap = el('div', {style: 'display: none', hidden: 'true', class: 'page-content'}); + const sampleClone = this.previewSampleElement.cloneNode() as HTMLElement; + sampleClone.textContent = this.definition.label; + wrap.append(sampleClone); + document.body.append(wrap); + + const propertiesToFetch = ['color', 'font-size', 'background-color', 'border-inline-start']; + const propertiesToReturn: Record = {}; + + const computed = window.getComputedStyle(sampleClone); + for (const property of propertiesToFetch) { + propertiesToReturn[property] = computed.getPropertyValue(property); + } + wrap.remove(); + + return propertiesToReturn; + } } \ No newline at end of file diff --git a/resources/js/wysiwyg/ui/framework/containers.ts b/resources/js/wysiwyg/ui/framework/containers.ts index 9ef59c72f..e58988e7b 100644 --- a/resources/js/wysiwyg/ui/framework/containers.ts +++ b/resources/js/wysiwyg/ui/framework/containers.ts @@ -30,11 +30,62 @@ export class EditorContainerUiElement extends EditorUiElement { } } -export class EditorFormatMenu extends EditorContainerUiElement { - buildDOM(): HTMLElement { - return el('div', { - class: 'editor-format-menu' - }, this.getChildren().map(child => child.getDOMElement())); +export class EditorSimpleClassContainer extends EditorContainerUiElement { + protected className; + + constructor(className: string, children: EditorUiElement[]) { + super(children); + this.className = className; } + protected buildDOM(): HTMLElement { + return el('div', { + class: this.className, + }, this.getChildren().map(child => child.getDOMElement())); + } +} + +export class EditorFormatMenu extends EditorContainerUiElement { + buildDOM(): HTMLElement { + const childElements: HTMLElement[] = this.getChildren().map(child => child.getDOMElement()); + const menu = el('div', { + class: 'editor-format-menu-dropdown editor-dropdown-menu editor-menu-list', + hidden: 'true', + }, childElements); + + const toggle = el('button', { + class: 'editor-format-menu-toggle', + type: 'button', + }, ['Formats']); + + const wrapper = el('div', { + class: 'editor-format-menu editor-dropdown-menu-container', + }, [toggle, menu]); + + let clickListener: Function|null = null; + + const hide = () => { + menu.hidden = true; + if (clickListener) { + window.removeEventListener('click', clickListener as EventListener); + } + }; + + const show = () => { + menu.hidden = false + clickListener = (event: MouseEvent) => { + if (!wrapper.contains(event.target as HTMLElement)) { + hide(); + } + } + window.addEventListener('click', clickListener as EventListener); + }; + + toggle.addEventListener('click', event => { + menu.hasAttribute('hidden') ? show() : hide(); + }); + menu.addEventListener('mouseleave', hide); + + return wrapper; + } } \ No newline at end of file diff --git a/resources/js/wysiwyg/ui/toolbars.ts b/resources/js/wysiwyg/ui/toolbars.ts index 0f46f5b2a..2d5063cf4 100644 --- a/resources/js/wysiwyg/ui/toolbars.ts +++ b/resources/js/wysiwyg/ui/toolbars.ts @@ -1,4 +1,4 @@ -import {EditorButton} from "./framework/buttons"; +import {EditorButton, FormatPreviewButton} from "./framework/buttons"; import { blockquote, bold, code, dangerCallout, @@ -9,25 +9,26 @@ import { undo, warningCallout } from "./defaults/button-definitions"; -import {EditorContainerUiElement, EditorFormatMenu} from "./framework/containers"; +import {EditorContainerUiElement, EditorFormatMenu, EditorSimpleClassContainer} from "./framework/containers"; +import {el} from "../helpers"; export function getMainEditorFullToolbar(): EditorContainerUiElement { - return new EditorContainerUiElement([ + return new EditorSimpleClassContainer('editor-toolbar-main', [ new EditorButton(undo), new EditorButton(redo), new EditorFormatMenu([ - new EditorButton(h2), - new EditorButton(h3), - new EditorButton(h4), - new EditorButton(h5), - new EditorButton(blockquote), - new EditorButton(paragraph), - new EditorButton(infoCallout), - new EditorButton(successCallout), - new EditorButton(warningCallout), - new EditorButton(dangerCallout), + new FormatPreviewButton(el('h2'), h2), + new FormatPreviewButton(el('h3'), h3), + new FormatPreviewButton(el('h4'), h4), + new FormatPreviewButton(el('h5'), h5), + new FormatPreviewButton(el('blockquote'), blockquote), + new FormatPreviewButton(el('p'), paragraph), + new FormatPreviewButton(el('p', {class: 'callout info'}), infoCallout), + new FormatPreviewButton(el('p', {class: 'callout success'}), successCallout), + new FormatPreviewButton(el('p', {class: 'callout warning'}), warningCallout), + new FormatPreviewButton(el('p', {class: 'callout danger'}), dangerCallout), ]), new EditorButton(bold), diff --git a/resources/sass/_editor.scss b/resources/sass/_editor.scss new file mode 100644 index 000000000..48912be8b --- /dev/null +++ b/resources/sass/_editor.scss @@ -0,0 +1,49 @@ +// Main UI elements +.editor-toolbar-main { + display: flex; +} + +// Buttons +.editor-button { + border: 1px solid #DDD; + font-size: 12px; + padding: 4px 6px; + color: #444; +} +.editor-button:hover { + background-color: #EEE; + cursor: pointer; + color: #000; +} +.editor-button-active, .editor-button-active:hover { + background-color: #ceebff; + color: #000; +} +.editor-button-format-preview { + padding: 4px 6px; + display: block; +} + +// Containers +.editor-dropdown-menu-container { + position: relative; +} +.editor-dropdown-menu { + position: absolute; + background-color: #FFF; + box-shadow: 0 0 6px 0 rgba(0, 0, 0, 0.15); + z-index: 99; + min-width: 120px; +} +.editor-menu-list { + display: flex; + flex-direction: column; +} +.editor-menu-list > .editor-button { + border-bottom: 0; + text-align: start; +} + +.editor-format-menu .editor-dropdown-menu { + min-width: 320px; +} \ No newline at end of file diff --git a/resources/sass/styles.scss b/resources/sass/styles.scss index f52b61992..636367e3a 100644 --- a/resources/sass/styles.scss +++ b/resources/sass/styles.scss @@ -15,6 +15,7 @@ @import "forms"; @import "animations"; @import "tinymce"; +@import "editor"; @import "codemirror"; @import "components"; @import "header"; diff --git a/resources/views/pages/parts/wysiwyg-editor.blade.php b/resources/views/pages/parts/wysiwyg-editor.blade.php index b48e10570..940c005b5 100644 --- a/resources/views/pages/parts/wysiwyg-editor.blade.php +++ b/resources/views/pages/parts/wysiwyg-editor.blade.php @@ -6,23 +6,19 @@ option:wysiwyg-editor:server-upload-limit-text="{{ trans('errors.server_upload_limit') }}" class=""> - +
+
+

Some content here

+

This has a link in it

+

List below this h2 header

+
    +
  • Hello
  • +
-
-

Some content here

-

This has a link in it

-

List below this h2 header

-
    -
  • Hello
  • -
- -

- Hello there, this is an info callout -

+

+ Hello there, this is an info callout +

+