Creating markdown field type : Full screen with preview

The current markdown editor field type in Laramanager is just OK. I really want a full screen mode with preview. In this post, I'll use UIkit, marked.js and highlight.js to make it happen.

View Project

In a previous post, I created a new core admin field called "Markdown". In this post, I want to update it with a preview/full-screen mode. Let's get started.

Instead of showing a small editor with a fullscreen option, I want always edit in full screen mode. So, my first thought is to create a fullscreen modal with a button to display it. UIKIt makes this easy. I'll use the fullscreen mode setup (https://getuikit.com/docs/modal#full-modifier) and add it in the markdown display field.

src/views/fields/markdown/field.blade.php

<a class="uk-button uk-button-default" href="#modal-full" uk-toggle>Edit</a>

<div id="modal-full" class="uk-modal-full" uk-modal>
    <div class="uk-modal-dialog">
        <button class="uk-modal-close-full uk-close-large" type="button" uk-close></button>
        ...
    </div>
</div>

This will show a full screen modal with a close button. Next, I'll add a 2 column layout showing the editor on the left and the preview on the right. Again, I'll use the input field helper built into Laramanager.

src/views/fields/markdown/field.blade.php

<div class="uk-modal-dialog">
    <button class="uk-modal-close-full uk-close-large" type="button" uk-close></button>
    <div class="uk-grid-collapse uk-child-width-1-2@s" uk-grid>
        <div class="uk-padding">
            @include('laramanager::partials.elements.form.textarea', [
                'field' => [
                    'name' => $field->slug,
                    'class' => 'field-markdown',
                    'id' => 'markdown-' . $field->id,
                    'value' => isset($entity) ? $entity->{$field->slug} : null
                ]
            ])
        </div>
        <div id="parsed-markdown-{{ $field->id }}" class="uk-padding" uk-height-viewport></div>
    </div>
</div>

Ok, now to setup the "Preview" panel on the right. I'll use a library called Marked.js to render the markdown and highlight.js to add syntax highlighting.

npm install marked --save

npm install hightlight.js --save

Then I'll load both libraries and setup some default options for the Marked library. These options will enable GFM mode and set the highlighting library (highlight.js).

window.marked = require('marked');
window.marked.setOptions({
    highlight: function(code) {
        return require('highlight.js').highlightAuto(code).value;
    },
    pedantic: false,
    gfm: true,
    tables: true,
    breaks: false,
    sanitize: false,
    smartLists: true,
    smartypants: false,
    xhtml: false
});

Before I setup the panels with the editor and preview, I need to make some HTML adjustments. Currently, I'm looping and initialling an editor on any field with the name "field-markdown". This would probably work fine if I didn't have a preview. But I need to update the preview on any change in the editor. In order to apply this event and update the preview panel, the editor and preview panel needs unquie IDs.

src/views/fields/markdown/field.blade.php

@include('laramanager::partials.elements.form.textarea', [
    'field' => [
        'name' => $field->slug,
        'class' => 'field-markdown',
        'id' => 'markdown-' . $field->id,
        'value' => isset($entity) ? $entity->{$field->slug} : null
    ]
])

Then enable the editor, add event and update preview on editor changes.

src/views/fields/markdown/scripts.blade.php

let editor = codemirror.fromTextArea(document.getElementById('markdown-{{ $field->id }}'), {
    mode: 'gfm',
    theme: "default"
})

editor.on('change', function(event) {
    document.getElementById('parsed-markdown-{{ $field->id }}').innerHTML = marked(editor.getValue());
})

Laramanager markdown field type full screen

It works! Well, at least the markdown editor with preview works. It doesn't save the content yet. Why? Well the "body" textarea/editor field is in the modal and not the form. So, I'll need to add a hidden field and update it with any changes made to the editor.

src/views/fields/markdown/field.blade.php

<input type="hidden" id="markdown-value-{{ $field->id }}" name="{{ $field->slug }}" value="{{ isset($entity) ? $entity->{$field->slug} : null }}">

src/views/fields/markdown/scripts.blade.php

editor.on('change', function(event) {
    document.getElementById('parsed-markdown-{{ $field->id }}').innerHTML = marked(editor.getValue());
    document.getElementById('markdown-value-{{ $field->id }}').value = editor.getValue();
})
Check out the code on Github - 9e45269.

That's it. I need to make some design updates but other than that, it should be ready to go.

2023 Phil Mareu - Coder, Traveler & Disc Thrower