laravel-notion-api icon indicating copy to clipboard operation
laravel-notion-api copied to clipboard

Blocks to markdown/html renderer

Open Gummibeer opened this issue 2 years ago • 3 comments

Is your feature request related to a problem? Please describe. Right now you can retrieve the content of a page (child blocks) with all the notion raw data, like annotations and so on. But In case you want to render it somewhere you will have manually go through all the blocks, apply the annotations and concatenate all blocks rendered output together.

Describe the solution you'd like I've started to create a collection of renderer classes transforming the different blocks and sub-entities to markdown. Markdown as it's short and easy to store in a database or file and can be used in different languages and has no definitions of how it's rendered, with which tags, classes or could even be used in non-HTML renderers.

Describe alternatives you've considered Markdown is probably not the best/most feature-complete option as Notion allows to colorize or underline text, both aren't possible with markdown. So HTML could be a better option - even if I would like to have the choice if HTML should be implemented. So a driver-based renderer and not forcing the user to use the one we picked.

Additional context Here's for example the RichTextRenderer which is one of the most common ones and would do the most work:

<?php

namespace App\Renderers;

use FiveamCode\LaravelNotionApi\Entities\PropertyItems\RichText;
use Illuminate\Support\Str;
use Illuminate\Support\Stringable;

class RichTextRenderer extends Renderer
{
    public function __construct(protected RichText $richText)
    {
    }

    public function render(): ?string
    {
        return collect($this->richText->getRawResponse())
            ->map(static function (array $data): string {
                return Str::of($data['plain_text'])
                    ->when(
                        $data['annotations']['italic'],
                        fn (Stringable $s) => $s->prepend('_')->append('_')
                    )
                    ->when(
                        $data['annotations']['bold'],
                        fn (Stringable $s) => $s->prepend('**')->append('**')
                    )
                    ->when(
                        $data['annotations']['strikethrough'],
                        fn (Stringable $s) => $s->prepend('~')->append('~')
                    )
                    ->when(
                        $data['annotations']['code'],
                        fn (Stringable $s) => $s->prepend('`')->append('`')
                    )
                    ->when(
                        $data['type'] === 'mention' && $data['mention']['type'] === 'page',
                        fn (Stringable $s) => $s->prepend('@[')->append("]({$data['mention']['page']['id']})")
                    );
            })
            ->implode('');
    }
}

Gummibeer avatar Jun 22 '23 11:06 Gummibeer

That is an amazing idea! Thank you very much for sharing @Gummibeer ! We thought about accurate access to rich-text entities a lot and put it on pause for other priority stuff. Really like the concept of having different drivers for rendering rich-text. As other things (like updating the version etc.) still have higher priority, I'll mark this as feature for the (hopefully) near future.

johguentner avatar Jul 18 '23 22:07 johguentner

As I already have some code here - if you would point me to the API you would want to provide I could potentially work on that one. Probably something like the PHP League commonmark. So a super simple entry point where you only pass in one block or a list of blocks and as a result receive HTML/Markdown/... Internally it could use a register of renderers that can even be overridden to handle all the different blocks. For example the link block could be very likely to be customized as I think that most people with the need to render the notion page would want a custom link instead of the notion page link.

Gummibeer avatar Jul 19 '23 09:07 Gummibeer