Creating a Bootstrap Grid.

The grid will be componsed of a block list for the columns and a few other fields as well.

The block list and an element type will be used to make the column creation dynamic.

Creating the column element type.

The column element type will be created with 4 fields.

  1. First Property (Column Size) will be a dropdown with a configuration Bootstrap Column - Size Options It will contain the following options.

    • Flexible (auto)
    • 12 Column (100%)
    • 11 Column (92%)
    • 10 Column (83%)
    • 9 Column (75%)
    • 8 Column (66%)
    • 7 Column (58%)
    • 6 Column (50%)
    • 5 Column (42%)
    • 4 Column (33%)
    • 3 Column (25%)
    • 2 Column (16%)
    • 1 Column (8%)
  2. Second Property (Custom Class) will be a text string.

  3. Third Property (Gutter Y) will be a dropdown with a configuration Bootstrap Column - Gutter Y

    • Inherit
    • No Gutter (gy-0)
    • (gy-1)
    • (gy-2)
    • (gy-3)
    • (gy-4)
    • (gy-5)
  4. Forth Property (Gutter X) will be a dropdown with a configuration Bootstrap Column - Gutter X

    • Inherit
    • No Gutter (gx-0)
    • (gx-1)
    • (gx-2)
    • (gx-3)
    • (gx-4)
    • (gx-5)

Our element type is completed. Feel free to add more properties for the column as needed.

Next we create and register the Row Block

We need two files for that. A Row.cshtml and a RowProperties.cs file.

The RowProperties.cs file will have the contents.

using BlockFarmEditor.Components.Blocks.BootstrapGrid;
using BlockFarmEditor.RCL.Library.Attributes;
using BlockFarmEditor.RCL.Models.BuilderModels;
using BlockFarmEditor.RCL.Models.ConfigModels;
using BlockFarmEditor.Umbraco.Models;
using Umbraco.Cms.Core.Models.Blocks;

[assembly: BlockFarmEditorContainer("blockfarmeditor.bootstrap-row", "Row", ViewPath = "~/Components/Blocks/BootstrapGrid/Row.cshtml", Icon = "folder", PropertiesType = typeof(RowProperties))]

namespace BlockFarmEditor.Components.Blocks.BootstrapGrid;

public class RowProperties : IBuilderProperties
{
    [BlockFarmEditorDataType("Dropdown", "Prefix")]
    [BlockFarmEditorDataTypeConfig(typeof(PrefixRowPropertiesConfig))]
    public string Prefix { get; set; } = "col-md";

    [BlockFarmEditorDataType("BlockList", "Columns")]
    public BlockListModel Columns { get; set; } = new BlockListModel([]);

    [BlockFarmEditorDataType("Dropdown", "Row Direction")]
    [BlockFarmEditorDataTypeConfig(typeof(DirectionRowPropertiesConfig))]
    public string RowDirection { get; set; } = string.Empty;

    [BlockFarmEditorDataType("Textsring", "Row Custom Class")]
    public string RowCustomCss { get; set; } = string.Empty;
}

public class PrefixRowPropertiesConfig : IBlockFarmEditorConfig
{
    public async Task<IEnumerable<BlockFarmEditorConfigItem>> GetItems()
    {
        return
        [
            new ()
            {
                Alias = "items",
                // Generate a list of name,value pairs for the dropdown items
                Value =new List<DropdownEditorConfigItem>() {
                    new("Extra Small (0px to 575px)", "col"),
                    new("Small (576px to 767px)", "col-sm"),
                    new("Medium (768px to 991px)", "col-md"),
                    new("Large (992px to 1199px)", "col-lg"),
                    new("Extra Large (1200px to 1399px)", "col-xl"),
                    new("Extra extra large (1400px)", "col-xxl")
                }
            },
            new ()
            {
                Alias = "multiple",
                Value = false // Assuming single selection for this example
            }
        ];
    }
}

public class DirectionRowPropertiesConfig : IBlockFarmEditorConfig
{
    public async Task<IEnumerable<BlockFarmEditorConfigItem>> GetItems()
    {
        return
        [
            new ()
            {
                Alias = "items",
                // Generate a list of name,value pairs for the dropdown items
                Value =new List<DropdownEditorConfigItem>() {
                    new("Left to Right", ""),
                    new("Right to Left", "flex-row-reverse")
                }
            },
            new ()
            {
                Alias = "multiple",
                Value = false // Assuming single selection for this example
            }
        ];
    }
}

The View Row.cshtml will have the following contents.

@using BlockFarmEditor.Components.Blocks.BootstrapGrid
@model RowProperties

@{
    var SizeMappings = (string columnSize) => Model.Prefix + (columnSize switch
    {
        "12 Column (100%)" => "-12",
        "11 Column (92%)" => "-11",
        "10 Column (83%)" => "-10",
        "9 Column (75%)" => "-9",
        "8 Column (66%)" => "-8",
        "7 Column (58%)" => "-7",
        "6 Column (50%)" => "-6",
        "5 Column (42%)" => "-5",
        "4 Column (33%)" => "-4",
        "3 Column (25%)" => "-3",
        "2 Column (16%)" => "-2",
        "1 Column (8%)" => "-1",
        _ => ""
    });

    var GutterYMappings = (string gutterY) => gutterY switch
    {
        "No Gutter (gy-0)" => "gy-0",
        "(gy-1)" => "gy-1",
        "(gy-2)" => "gy-2",
        "(gy-3)" => "gy-3",
        "(gy-4)" => "gy-4",
        "(gy-5)" => "gy-5",
        _ => ""
    };

    var GutterXMappings = (string gutterX) => gutterX switch
    {
        "No Gutter (gx-0)" => "gx-0",
        "(gx-1)" => "gx-1",
        "(gx-2)" => "gx-2",
        "(gx-3)" => "gx-3",
        "(gx-4)" => "gx-4",
        "(gx-5)" => "gx-5",
        _ => ""
    };
}

<div class="row @Model.RowDirection @Model.RowCustomCss">
    @foreach (var column in Model.Columns)
    {
        dynamic item = column.Content;
        <div class="@SizeMappings(item.ColumnSize) @GutterYMappings(item.GutterY) @GutterXMappings(item.GutterX) @item.CustomClass">
            <block-area identifier="column-@(item.Key.ToString("N").Substring(0, 8))"></block-area>
        </div>
    }
</div>

Your block is now ready for use.