Dynamic styling options for Elemental blocks

I have found that the Style option in the Elemental module is a bit limited, especially when you want to offer the ability to adjust more than one style or formatting option, e.g. background, margin, padding. Making do with a single dropdown field is cumbersome.

Obviously, we could just add these extra fields to the Base Element and go from there. But when you have many different Elements and they may require different styling on a case by case basis, you need a bit of flexibility.

I have developed an extension that allows you to dynamically populate the styling options so you can have individual dropdown fields for background, padding, margin, or whatever you can think of. Each dropdown will consist of an array of [cssClass(es) => Title] in the same manner as the Style option.

This is early days and has not been fully tested but I was excited at the possibilities so have pasted it here. Use at your own discretion.

Add this extension to the BaseElement module, in your config.yml file

DNADesign\Elemental\Models\BaseElement:
  extensions:
    - Jellygnite\Elements\Extensions\BaseElementExtension

and you can either use the yml file to build your styles. You can add different styles for different Elements, e.g.

DNADesign\Elemental\Models\ElementContent:
  extra_styles:
    MarginLeft:
      'Title': 'Margin Left'
      'Description': 'Adjust the margin on the left side'
      'Styles':
        'ml-0': 'None'
        'ml-4': 'Small'

or do it in the extension:

<?php

namespace Jellygnite\Elements\Extensions;

use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\DropdownField;
use SilverStripe\Forms\ReadonlyField;
use SilverStripe\Forms\Tab;
use SilverStripe\Forms\TextField;
use SilverStripe\ORM\DataExtension;
use DNADesign\Elemental\Models\BaseElement;
use SilverStripe\Control\Controller;
use SilverStripe\Dev\Debug;

class BaseElementExtension extends DataExtension 
{


	// flexible array of styles that can be used for any element
	// ensure each has Title and Styles
    private static $extra_styles = [
		'Background' => [
			'Title' => 'Background',
			'Description' => '',
			'Styles' => [
				'' => 'Inherit',
				'bg-default' => 'Default',
			]
		],
		'Padding' => [
			'Title' => 'Padding',
			'Description' => 'Adjust the padding on all sides',
			'Styles' => [
				'p-0' => 'None',
				'p-4' => 'Small',
				'p-6' => 'Medium',
				'p-8' => 'Large',
			]
		],
		'Margin' => [
			'Title' => 'Margin',
			'Description' => 'Adjust the margins on all sides',
			'Styles' => [
				'm-0' => 'None',
				'm-4' => 'Small',
				'm-6' => 'Medium',
				'm-8' => 'Large',
			]
		]
	];


    private static $db = [
        'ExtraStyle' => 'Text'  // saves a json object with all values
    ];


    public function updateCMSFields(FieldList $fields) {
		
		
        $fields->insertAfter(Tab::create('Appearance', 'Appearance'), 'Settings');
        $fields->removeByName('ExtraStyle');
		
        $extra_styles = $this->owner->config()->get('extra_styles');
		$extra_style_values = json_decode($this->owner->ExtraStyle, true);


            if ($extra_styles && count($extra_styles) > 0) {
				foreach($extra_styles as $index => $style){
	                $styleDropdown = DropdownField::create($index, $style['Title'], $style['Styles'], ((is_array($extra_style_values) && array_key_exists($index, $extra_style_values)) ? $extra_style_values[$index] : null)); 
					$styleDropdown->setRightTitle($style['Description']);
					$fields->addFieldToTab(
						'Root.Appearance',
						$styleDropdown 
					);
                	$styleDropdown->setEmptyString(_t(__CLASS__.'.CUSTOM_STYLES', 'Select a style..'));
				}
				$fields->addFieldToTab(
					'Root.Appearance',
					ReadonlyField::create('ExtraStyle','ExtraStyle')
				);
            } 
			
    }



	
    public function updateStyleVariant(&$style)
	{
		$extra_style_values = json_decode($this->owner->ExtraStyle, true);
		
		if ($extra_style_values && count($extra_style_values) > 0) {
			foreach($extra_style_values as $index => $css_class){
				$style .= $css_class?' ' . $css_class:'';
			}
		}
		
    }
	
	
    public function onBeforeWrite()
    {
        parent::onBeforeWrite();
		
		$request = Controller::curr()->getRequest();
		$postVars = $request->postVars();
		$extra_style_values = [];
		
		$extra_styles = $this->owner->config()->get('extra_styles');
		if ($extra_styles && count($extra_styles) > 0) {
			foreach($extra_styles as $index => $style){
				$extra_style_values[$index] = $request->postVars()[$index];
			}
		} else {
			
		}
		
		$this->owner->ExtraStyle = json_encode($extra_style_values);		
		
    }

}

I have reworked this whole thing and am uploading this as a module to github very soon.

Please try it out and let me know if any issues or if you have feedback:

composer require jellygnite/silverstripe-elemental-style