Maelstrom CMS Toolkit

A CMS toolkit for intermediate to advanced development teams who love React, Tailwind & Laravel.

Maelstrom is a collection of Laravel and React components to help you flesh out your own control panels using as much of vanilla Laravel as possible.

Screenshot of Maelstrom in action.

Why use Maelstrom?

Unlike other solutions such as Nova - Maelstrom doesn't impose any ways on doing things, we simply provide you various helpers to either use, or ignore - allowing you to implement things exactly as you need. Utilising the IoC container, waterfall includes, extendable UI components and a controversial god class, everything can be changed to suit your needs with ease.

The Stack

Maelstrom uses a cutting edge stack to afford you the ability to create the most advanced systems, unlike many other systems we don't use any Bootstrap themes, it's a pure utility class based interface using Tailwind and the UI library from Ant Design to allow you to create what ever you need.

Laravel 5.7+

Maelstrom is based on the incredibly developer friendly Laravel, we use as much of vanilla Laravel as possible which means if Laravel allows you to do it, then we allow you to do it. We even use the Mix asset pipeline to allow you the up-most control.

React 16+

We love Vue, but the React eco-system is beautifully rich, so by opting for React you have access to a plethora of extremely durable libraries, including Ant - and by using the class syntax, everything is easily extendable to make your own modifications.

Ant Design

Possible one of the most modern and eye-catching design systems currently available, with a myriad of highly flexible components to build your systems. We use only a handful of their features, however you have access to use them all!

Tailwind

Not forgetting the incredible Tailwind, avoiding the path of themes and going down a utility route, allows you to have the most customised UIs possible, we impose no design restrictions on you, letting you write as much or as little code as you like.

Features

Before Maelstrom existed, we'd experienced a whole range of systems, finding what was good, what was bad, and now we've stolen them and put them all together, creating a library of features to make your development process and user experience as smooth as possible. (That's right, we even have breadcrumbs - Looking at you Nova!)

Below is a list of just some of our bundled functionality - See our documentation for a full list and our ~30 field types.

Media Manager
Tabbed Forms
Repeatable Inputs
Nested Resources
Sidebar Manager
Flash Messages
Breadcrumbs
Validation
Colour Pickers
Date / Time Pickers
File / Image Uploaders
Markdown and Wysiwyg
Video Fields
Tagging Inputs
Selects and Multi-Selects
Randomisers
Ratings
Radio Buttons w/ Visibility Toggle
Algolia Places
Toggles / Switches
Edit Account Page
Trash and Soft Deletes
Filters and Searches
Bulk Actions

How easy is it?

Creating a panel is incredibly straight forward, you just need the normal set of components, e.g. a route, a controller, a model and some templates.

We've even created a short video series walking you through creating a backend for your own blog.

Videos

Below you can also see a bare minimal example of what this might look like below.

Code:

// PostController.php
class PostController extends Controller
{
    protected $panel;
    
    public function __construct()
    {
        $this->panel = maelstrom(Post::class)
    }
    
    public function index()
    {
        return view('posts.index')->with([
            'entries' => $this->panel->getEntries(),
            'columns' => [
                [
                    'label' => 'Name',
                    'dataIndex' => 'post_name',
                    'type' => 'EditLinkColumn',
                    'sortable' => true,
                    'searchable' => true,
                ],
                [
                    'label' => 'Featured',
                    'dataIndex' => 'is_featured',
                    'type' => 'BooleanColumn',
                    'align' => 'center',
                ],
            ]
        ]);
    }
    
    public function create()
    {
        return view('posts.form')->with([
            'action' => route('posts.store'),
            'method' => 'POST',
        ]);
    }
    
    public function store(Request $request)
    {
        $request->validate([
            'name' => 'required',
        ]);
        
        $post = $this->panel->store('Woo page created!');
        
        return redirect()->route('posts.edit', $post);
    }
    
    public function edit(Post $post)
    {
        $this->panel->setEntry($post);
        
        return view('posts.form')->with([
            'action' => route('posts.update'),
            'method' => 'PUT',
        ]);
    }
    
    public function update(Request $request, Post $post)
    {
        $request->validate([
            'name' => 'required',
        ]);
        
        $post = $this->panel->update('Your page has been updated!');
        
        return redirect()->route('posts.edit', $post);
    }
    
    public function destroy(Post $post)
    {
        $post->delete();
        
        return redirect()->route('posts.index');
    }
}
// posts.index.blade.php
@extends('maelstrom::layouts.index')

@section('buttons')
    @include('maelstrom::buttons.button', [
        'url' => route('posts.create'),
        'label' => 'Create Post'
    ])
@endsection
// posts.form.blade.php
@extends('maelstrom::layouts.form')

@section('content')
    @component('maelstrom::components.form', [
        'action' => $action,
        'method' => $method,
    ])
    
        @include('maelstrom::inputs.text', [
            'label' => 'Post Name',
            'name' => 'post_name',
            'required' => true,
        ])
        
        @include('maelstrom::inputs.text', [
            'label' => 'Post Slug',
            'name' => 'slug',
            'required' => true,
            'html_type' => 'url',
        ])
        
        @include('maelstrom::inputs.wysiwyg', [
            'label' => 'Post Body',
            'name' => 'body',
            'required' => true,
        ])
        
        @include('maelstrom::inputs.switch', [
            'label' => 'Featured on Homepage?',
            'name' => 'is_featured',
        ])
        
        @include('maelstrom::components.media_manager', [
            'label' => 'Header Image',
            'name' => 'header_image',
            'max_items' => 1
        ])
    
    @endcomponent
    
@endsection

Browser:

Preview of the resource index.
Preview of a form.

Pricing

This all sounds great, but how much does it cost?

Technically nothing, all the source code is open-source and can be used commercially for free. However we would appreciate any donations to help support the on-going maintenance of the toolkit - so you can pay however much you feel we deserve.

Pay what you want.

Support