Lexical: Started loading real content, Improved html loading

Added more styling/layout for buttons and main content area
This commit is contained in:
Dan Brown 2024-07-01 15:10:22 +01:00
parent c2ecbf071f
commit 9ebbf7ce94
No known key found for this signature in database
GPG Key ID: 46D9F943C24A2EF9
6 changed files with 45 additions and 53 deletions

View File

@ -5,10 +5,10 @@ export class WysiwygEditor extends Component {
setup() { setup() {
this.elem = this.$el; this.elem = this.$el;
this.editContainer = this.$refs.editContainer; this.editContainer = this.$refs.editContainer;
this.editContent = this.$refs.editContent; this.input = this.$refs.input;
window.importVersioned('wysiwyg').then(wysiwyg => { window.importVersioned('wysiwyg').then(wysiwyg => {
const editorContent = this.editContent.textContent; const editorContent = this.input.value;
wysiwyg.createPageEditorInstance(this.editContainer, editorContent); wysiwyg.createPageEditorInstance(this.editContainer, editorContent);
}); });
} }

View File

@ -1,17 +1,32 @@
import {$getRoot, LexicalEditor} from "lexical"; import {$createParagraphNode, $getRoot, $isTextNode, LexicalEditor} from "lexical";
import {$generateHtmlFromNodes, $generateNodesFromDOM} from "@lexical/html"; import {$generateHtmlFromNodes, $generateNodesFromDOM} from "@lexical/html";
import {$createCustomParagraphNode} from "./nodes/custom-paragraph";
export function setEditorContentFromHtml(editor: LexicalEditor, html: string) { export function setEditorContentFromHtml(editor: LexicalEditor, html: string) {
const parser = new DOMParser(); const parser = new DOMParser();
const dom = parser.parseFromString(html, 'text/html'); const dom = parser.parseFromString(html, 'text/html');
console.log(html);
editor.update(() => { editor.update(() => {
const nodes = $generateNodesFromDOM(editor, dom); // Empty existing
const root = $getRoot(); const root = $getRoot();
for (const child of root.getChildren()) { for (const child of root.getChildren()) {
child.remove(true); child.remove(true);
} }
const nodes = $generateNodesFromDOM(editor, dom);
// Wrap top-level text nodes
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i];
if ($isTextNode(node)) {
const paragraph = $createCustomParagraphNode();
paragraph.append(node);
nodes[i] = paragraph;
}
}
root.append(...nodes); root.append(...nodes);
}); });
} }

View File

@ -29,8 +29,12 @@ export function createPageEditorInstance(container: HTMLElement, htmlContent: st
const editArea = el('div', { const editArea = el('div', {
contenteditable: 'true', contenteditable: 'true',
class: 'editor-content-area page-content',
}); });
container.append(editArea); const editWrap = el('div', {
class: 'editor-content-wrap',
}, [editArea]);
container.append(editWrap);
container.classList.add('editor-container'); container.classList.add('editor-container');
const editor = createEditor(config); const editor = createEditor(config);

View File

@ -51,7 +51,7 @@ export class EditorButton extends EditorUiElement {
const label = this.getLabel(); const label = this.getLabel();
let child: string|HTMLElement = label; let child: string|HTMLElement = label;
if (this.definition.icon) { if (this.definition.icon) {
child = el('span', {class: 'editor-button-icon'}); child = el('div', {class: 'editor-button-icon'});
child.innerHTML = this.definition.icon; child.innerHTML = this.definition.icon;
} }

View File

@ -14,6 +14,9 @@
.editor-toolbar-main { .editor-toolbar-main {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: center;
border-top: 1px solid #DDD;
border-bottom: 1px solid #DDD;
} }
body.editor-is-fullscreen { body.editor-is-fullscreen {
@ -22,13 +25,24 @@ body.editor-is-fullscreen {
z-index: 20; z-index: 20;
} }
} }
.editor-content-area {
&:focus {
outline: 0;
}
}
.editor-content-wrap {
overflow-y: scroll;
}
// Buttons // Buttons
.editor-button { .editor-button {
border: 1px solid #DDD;
font-size: 12px; font-size: 12px;
padding: 4px 6px; padding: 4px 6px;
color: #444; color: #444;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
} }
.editor-button:hover { .editor-button:hover {
background-color: #EEE; background-color: #EEE;
@ -38,7 +52,6 @@ body.editor-is-fullscreen {
.editor-button[disabled] { .editor-button[disabled] {
pointer-events: none; pointer-events: none;
cursor: not-allowed; cursor: not-allowed;
background-color: #EEE;
opacity: .6; opacity: .6;
} }
.editor-button-active, .editor-button-active:hover { .editor-button-active, .editor-button-active:hover {
@ -52,7 +65,8 @@ body.editor-is-fullscreen {
.editor-button-icon svg { .editor-button-icon svg {
width: 24px; width: 24px;
height: 24px; height: 24px;
fill: #000; color: inherit;
fill: currentColor;
} }
// Containers // Containers

View File

@ -4,55 +4,14 @@
option:wysiwyg-editor:text-direction="{{ $locale->htmlDirection() }}" option:wysiwyg-editor:text-direction="{{ $locale->htmlDirection() }}"
option:wysiwyg-editor:image-upload-error-text="{{ trans('errors.image_upload_error') }}" option:wysiwyg-editor:image-upload-error-text="{{ trans('errors.image_upload_error') }}"
option:wysiwyg-editor:server-upload-limit-text="{{ trans('errors.server_upload_limit') }}" option:wysiwyg-editor:server-upload-limit-text="{{ trans('errors.server_upload_limit') }}"
class=""> class="flex-container-column flex-fill">
<div class="editor-container" refs="wysiwyg-editor@edit-container"> <div class="editor-container flex-container-column flex-fill" refs="wysiwyg-editor@edit-container">
</div> </div>
<script type="text/html" refs="wysiwyg-editor@edit-content">
<p id="Content!">Some <strong>content</strong> here</p>
<p>Content with image in, before text. <img src="https://bookstack.local/bookstack/uploads/images/gallery/2022-03/scaled-1680-/cats-image-2400x1000-2.jpg" width="200" alt="Sleepy meow"> After text.</p>
<p>This has a <a href="https://example.com" target="_blank" title="Link to example">link</a> in it</p>
<h2>List below this h2 header</h2>
<ul>
<li>Hello</li>
</ul>
<details>
<summary>Collapsible details/summary block</summary>
<p>Inner text here</p>
<h4>Inner Header</h4>
<p>More text <strong>with bold in</strong> it</p>
</details>
<p class="callout info">
Hello there, this is an info callout
</p>
<h3>Table</h3>
<table>
<thead>
<tr>
<th>Cell A</th>
<th>Cell B</th>
<th>Cell C</th>
</tr>
</thead>
<tbody>
<tr>
<td>Cell D</td>
<td>Cell E</td>
<td>Cell F</td>
</tr>
</tbody>
</table>
</script>
<div id="lexical-debug" style="white-space: pre-wrap; font-size: 12px; height: 200px; overflow-y: scroll; background-color: #000; padding: 1rem; border-radius: 4px; color: #FFF;"></div> <div id="lexical-debug" style="white-space: pre-wrap; font-size: 12px; height: 200px; overflow-y: scroll; background-color: #000; padding: 1rem; border-radius: 4px; color: #FFF;"></div>
{{-- <textarea id="html-editor" name="html" rows="5"--}} <textarea refs="wysiwyg-editor@input" id="html-editor" hidden="hidden" name="html" rows="5">{{ old('html') ?? $model->html ?? '' }}</textarea>
{{-- @if($errors->has('html')) class="text-neg" @endif>@if(isset($model) || old('html')){{ old('html') ? old('html') : $model->html }}@endif</textarea>--}}
</div> </div>
@if($errors->has('html')) @if($errors->has('html'))