jacksleight / statamic-bard-mutator

This Statamic addon allows you to modify the data and tags rendered by the Bard fieldtype, giving you full control over the final HTML.
https://statamic.com/addons/jacksleight/bard-mutator
MIT License
19 stars 3 forks source link

Advanced data helpers #26

Closed jacksleight closed 2 months ago

daun commented 2 months ago

Interesting! Just saw the figure blockquote example. Very succinct solution. I've ended up with a workable solution but it's not very grokkable or maintainable. It requires adding figure and figcaption nodes to Bard itself and a lot of cloning :(

class SemanticBlockquotes
{
    public function __invoke(string|array $sourcePrefix = ['-', '–', '—']): void
    {
        // Make sure TipTap knows how to render a <figure>
        Augmentor::replaceExtension('figure', function ($existing) {
            return $existing ?? new \App\Bard\Nodes\Figure;
        });

        // Make sure TipTap knows how to render a <figcaption>
        Augmentor::replaceExtension('figcaption', function ($existing) {
            return $existing ?? new \App\Bard\Nodes\Figcaption;
        });

        // Wrap blockquote inside <figure>
        Mutator::data('blockquote', function ($data, $meta) use ($sourcePrefix) {
            // Skip if blockquote is already inside a figure
            if ($meta['parent']->type === 'figure') return;

            // Clone blockquote and turn into figure
            $blockquote = clone $data;
            $data->type = 'figure';
            $data->content = [$blockquote];

            // Read author/source from last paragraph
            $paragraph = Arr::last($blockquote->content, fn($node) => $node->type === 'paragraph');
            $source = Arr::last($paragraph->content ?? [], fn($node) => $node->type === 'text' && Str::startsWith($node->text, $sourcePrefix));

            if ($source) {
                // Remove source prefix
                $source->text = Str::ltrim(Str::chopStart($source->text, $sourcePrefix));

                // Turn source into figcaption
                $paragraph->type = 'figcaption';

                // Move figcaption one level up from blockquote to figure
                $blockquote->content = Arr::where($blockquote->content, fn($node) => $node !== $paragraph);
                $data->content[] = $paragraph;
            }
        });
    }
}
jacksleight commented 2 months ago

Yep, it was actually your question that inspired these additions. As you've found it is technically possible at the moment, but it's not super straightforward, this should make it much simpler.

This is draft because I'm still deciding on the right API for the new helpers, but once I have it nailed I'll get it released.