Skip to content
/ mason Public

A simple block based drag and drop page / document builder field for Filament.

License

Notifications You must be signed in to change notification settings

awcodes/mason

Repository files navigation

mason opengraph image

Latest Version on Packagist GitHub Tests Action Status Total Downloads

Mason

A simple block based drag and drop page / document builder field for Filament.

Compatibility

Package Version Filament Version
0.x 3.x
1.x 4.x

Upgrading

Please see the UPGRADE guide for instructions on upgrading from 0.x to 1.x as there are breaking changes.

Installation

You can install the package via composer:

composer require awcodes/mason

In an effort to align with Filament's theming methodology you will need to use a custom theme to use this plugin.

Important

If you have not set up a custom theme and are using Filament Panels follow the instructions in the Filament Docs first. The following applies to both the Panels Package and the standalone Tables package.

After setting up a custom theme add the plugin's css to your theme css file or your app's css file if using the standalone forms package.

@import '../../../../vendor/awcodes/mason/resources/css/plugin.css';

@source '../../../../vendor/awcodes/mason/resources/**/*.blade.php';

Configuration

You can publish the config file with:

php artisan vendor:publish --tag="mason-config"

This is the contents of the published config file:

return [
    'generator' => [
        'namespace' => 'App\\Mason',
        'views_path' => 'mason',
    ],
];

Usage

Important

Since Mason uses json to store its data in the database you will need to make sure your model's field is cast to 'array' or 'json'.

Warning

Due to an issue with Livewire and full page components, at the moment any Bricks that have Livewire components rendered in a blade view will not work properly inside the editor when loading a resource for editing. The only workaround at the moment is to have a dedicated preview blade that does not use either the @livewire or <livewire: directives. This only affects the editor view. The front end rendering will work as expected.

Form Field

In your Filament forms you should use the Mason component. The Mason component accepts a name prop which should be the name of the field in your model, and requires an array of actions that make up the 'bricks' available to the editor.

use Awcodes\Mason\Mason;
use Awcodes\Mason\Bricks\Section;

->schema([
    Mason::make('content')
        ->bricks([
            Section::class,
        ])
        // optional
        ->placeholder('Drag and drop bricks to get started...')
        ->doubleClickToEdit(),
])

Infolist Entry

In your Filament infolist you should use the MasonEntry component. The Mason component accepts a name prop which should be the name of the field in your model.

use Awcodes\Mason\MasonEntry;
use Awcodes\Mason\Bricks\Section;

->schema([
    MasonEntry::make('content')
        ->bricks([
            Section::class,
        ])
])            

To keep from having to repeat yourself when assigning bricks to the editor and the entry it would help to create sets of bricks that make sense for their use case. Then you can just use that in the bricks method.

class BrickCollection
{
    public static function make(): array
    {
        return [
            NewsletterSignup::class,
            Section::class,
            Cards::class,
            SupportCenter::class,
        ];
    }
}

Mason::make('content')
    ->bricks(BrickCollection::make())

MasonEntry::make('content')
    ->bricks(BrickCollection::make())

Creating Bricks

Bricks are nothing more than Filament actions that have an associated view that is rendered in the editor with its data.

To help you get started there is a make:mason-brick command that will create a new brick for you with the necessary class and blade template in the paths specified in the config file.

php artisan make:mason-brick Section

This will create a new brick in the App\Mason namespace with the class Section and a preview and index blade template in the resources/views/mason directory. Bricks follow the same conventions as Filament RichEditor custom blocks.

use Awcodes\Mason\Brick;
use Filament\Actions\Action;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\Radio;
use Filament\Forms\Components\RichEditor;
use Filament\Forms\Components\ToggleButtons;
use Filament\Schemas\Components\Grid;
use Filament\Schemas\Components\Section as FilamentSection;
use Filament\Support\Icons\Heroicon;
use Illuminate\Contracts\Support\Htmlable;
use Illuminate\Support\HtmlString;
use Throwable;

class Section extends Brick
{
    public static function getId(): string
    {
        return 'section';
    }
    
    public static function getLabel(): string
    {
        return parent::getLabel();
    }

    public static function getPreviewLabel(array $config): string
    {
        return static::getLabel();
    }

    public static function getIcon(): string | Heroicon | Htmlable | null
    {
        return new HtmlString('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 20h.01M4 20h.01M8 20h.01M12 20h.01M16 20h.01M20 4h.01M4 4h.01M8 4h.01M12 4h.01M16 4v.01M4 9a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1z"/></svg>');
    }

    /**
     * @throws Throwable
     */
    public static function toPreviewHtml(array $config): ?string
    {
        return static::toHtml($config, []);
    }

    /**
     * @throws Throwable
     */
    public static function toHtml(array $config, array $data): ?string
    {
        return view('mason::bricks.section.index', [
            'background_color' => $config['background_color'] ?? 'white',
            'image' => $config['image'] ?? null,
            'text' => $config['text'] ?? null,
        ])->render();
    }

    public static function configureBrickAction(Action $action): Action
    {
        return $action
            ->slideOver()
            ->schema([
                Radio::make('background_color'),
                FileUpload::make('image'),
                RichEditor::make('text'),
            ]);
    }
}

Rendering Content

You are free to render the content however you see fit. The data is stored in the database as json so you can use the data however you see fit. But the plugin offers a helper method for converting the data to html should you choose to use it.

Similar to the form field and entry components the helper needs to know what bricks are available. You can pass the bricks to the helper as the second argument. See, above about creating a collection of bricks. This will help keep your code DRY.

{!! mason(content: $post->content, bricks: \App\Mason\BrickCollection::make())->toHtml() !!}

There is also a dedicated Render that can be used if you need more control over the rendering process.

use Awcodes\Mason\Support\MasonRenderer;

$renderer = MasonRenderer::make($content)->bricks(\App\Mason\BrickCollection::make());

$renderer->toHtml()
$renderer->toUnsafeHtml();
$renderer->toArray();
$renderer->toText();

Faking Content

When testing you may want to fake some Mason content. There is a helper method for that as well.

use Awcodes\Mason\Support\Faker;

Faker::make()
    ->brick(
        id: 'section',
        config: [
            'background_color' => 'white',
            'text' => '<h2>This is a heading</h2><p>Just some random text for a paragraph</p>',
            'image' => null,
        ]
    )
    ->brick(
        id: 'section',
        config: [
            'background_color' => 'primary',
            'text' => '<h2>This is a heading</h2><p>Just some random text for a paragraph</p>',
            'image' => null,
        ]
    )
    ->asJson(),

Testing

composer test

Changelog

Please see CHANGELOG for more information on what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Security Vulnerabilities

Please review our security policy on how to report security vulnerabilities.

Credits

License

The MIT License (MIT). Please see License File for more information.

About

A simple block based drag and drop page / document builder field for Filament.

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Sponsor this project

 

Packages

No packages published