Aurora.Uix.Layout.Blueprint (Aurora UIX v0.1.0)

Comprehensive layout configuration system for dynamic UI generation.

Provides DSL macros for defining declarative, nested, and flexible UI structure for Phoenix LiveView. Supports compile-time layout generation and field arrangement for index, form, and show views.

Layout Hierarchy

  • Container Layouts: Index, Form, Show
  • Sub-Layouts: Inline, Stacked, Group, Sections, Section

Layout Containers

  1. Index: Horizontal field arrangement
  2. Form: Editable field layout
  3. Show: Read-only field display

Sub-Layout Types

  • inline: Horizontal field grouping
  • stacked: Vertical field arrangement
  • group: Visually segmented fields
  • sections: Tab-like field organization
  • section: Tab contents

Layout Tree Element Structure

Internally, each layout is represented by a list of maps (called "paths"), where each entry contains the following keys:

  • :tag (atom): The layout command. Possible values include:

    • Container commands: :index, :form, :show
    • Sub-layout commands: :stacked, :group, :inline, :sections and section
  • :name (atom): For container layouts (:index, :form, and :show), this key is required and holds the resource configuration name to which the layout applies. For sub-layout commands, this key is not required.

  • :state (atom): Indicates the beginning (:start) or ending (:end) of a layout block.

  • :opts (keyword list): Contains additional options for customizing the layout (for example, UI overrides such as field length or custom renderers).

  • :config (tuple or map): Holds specific configuration data:

    • For field lists: {:fields, fields} where fields is a list of field identifiers.
    • For groups: {:title, "Group Title"}.
    • For sections: {:title, "Section Title"} or other configuration as needed.
    • Other commands may store custom configuration information here.

Usage Examples

Basic Usage

The simplest usage creates an index layout for listing resources and a default form layout containing all enabled fields:

  defmodule ProductViews do
    alias MyApp.Inventory
    alias MyApp.Inventory.Product

    auix_resource_metadata(:product, context: Inventory, schema: Product)

    auix_create_ui
  end

Custom Layout for Index and Form

Customize the index view to display only selected columns, and define a form layout with an inline group of fields:

  defmodule ProductViews do
    alias MyApp.Inventory
    alias MyApp.Inventory.Product

    auix_resource_metadata(:product, context: Inventory, schema: Product)

    auix_create_ui do
      index_columns :product, [:reference, :name]
      edit_layout :product do
        inline [:reference, :name, :description]
      end
    end
  end

Using Sub-Layouts in Form and Show

Within form and show containers, structure the UI using sub-layout commands such as stacked, group, and inline:

  defmodule ProductViews do
    alias MyApp.Inventory
    alias MyApp.Inventory.Product

    auix_resource_metadata(:product, context: Inventory, schema: Product)

    auix_create_ui do
      edit_layout :product do
        inline do
          group "Identification", [:reference, :name, :description]
          stacked [:quantity_initial, :quantity_entries, :quantity_exits, :quantity_at_hand]
        end
        group "Dimensions", [:height, :width, :length]
      end

      show_layout :product do
        inline [:reference, :name, :description]
      end
    end
  end

Using Section Layouts

Divide the form or show layout into distinct tabs using sections. Each section represents a tab where only its fields are visible when selected:

  defmodule ProductViews do
    alias MyApp.Inventory
    alias MyApp.Inventory.Product

    auix_resource_metadata(:product, context: Inventory, schema: Product)

    auix_create_ui do
      edit_layout :product do
        sections do
          section "Details", [:reference, :name, :description]
          section "Prices", [:msrp, :rrp, :list_price]
          section "Images", [:image, :thumbnail]
        end
      end
    end
  end

Overriding Field Options

Customize UI characteristics for specific fields by supplying keyword options:

  defmodule ProductViews do
    alias MyApp.Inventory
    alias MyApp.Inventory.Product

    auix_resource_metadata(:product, context: Inventory, schema: Product)

    auix_create_ui do
      index_columns :product, [:reference, name: [renderer: &upcase_text/1]]
      edit_layout :product do
        inline [id: [hidden: true], reference: [readonly: true, length: 30], description: [length: 255]]
      end
    end
  end

Fields can be framed within a named group.

  defmodule ProductViews do
    alias MyApp.Inventory
    alias MyApp.Inventory.Product

    auix_resource_metadata(:product, context: Inventory, schema: Product)

    auix_create_ui do
      edit_layout :product do
        group "Identification", [:reference, :name, :description]
        group "Quantities", [:quantity_initial, :quantity_entries, quantity_exits, quantity_at_hand]
        group "Dimensions", [:height, :width, :length]
      end
    end
  end

Complex Layouts

Layout can be more complex, by combining sections, groups, inline and field UI overrides.

  defmodule ProductViews do
    alias MyApp.Inventory
    alias MyApp.Inventory.Product

    auix_resource_metadata(:product, context: Inventory, schema: Product)

    auix_create_ui do
      edit_layout :product do
        sections do
          section "Details" do
            inline do
              inline [id: [hidden: true]]
              group "Identification" do
                inline [reference: [readonly: true]]
                inline [:name, :description]
              end
              group "Quantities", [:quantity_initial, :quantity_entries, quantity_exits, quantity_at_hand]
            end

            group "Dimensions", [:height, :width, :length]
          end

          section "Prices", [:msrp, :rrp, :list_price]
          section "Images", [:image, :thumbnail]
        end
      end
    end

Summary

Functions

Generates a default layout_tree structure for rendering UI components based on the given layout type.

Defines a form layout for resource editing.

Defines a group sub-layout to visually segment related fields under a common title.

Registers index columns and associated options for a specific resource.

Defines an inline sub-layout that groups fields horizontally within a form or show container.

Parses a list of paths to handle sections based on the given layout type.

Defines a section within a sections container, representing a tab that contains a specific set of fields.

Defines a sections container that groups multiple section entries into tab-like structures.

Defines a read-only layout for resource display.

Defines a stacked sub-layout that groups fields vertically within a form or show container.

Functions

build_default_layout_paths(list, resource_config, opts, layout_type)

@spec build_default_layout_paths(list(), map(), keyword(), atom()) ::
  Aurora.Uix.TreePath.t()

Generates a default layout_tree structure for rendering UI components based on the given layout type.

Parameters

  • paths (list()): An existing list of paths. If empty, default paths are generated.
  • resource_config (atom()): The associated resource configuration.
  • layout_type (atom()): The rendering layout type (:index, :form, or :show).

Returns

  • map(): A map representing the UI structure.

Modes and Behaviour

  • :index layout types: Generates an :index structure using all available fields as columns.
  • :form and :show layout types: Generates a :layout structure containing an :inline group with all fields.
  • If paths are already provided, they are returned unchanged.

Example

iex> Aurora.Uix.Layout.Blueprint.build_default_layout_paths([], "product", %{fields: [%{field: :name}, %{field: :price}]}, [], :index) [

%{tag: :index, state: :start, opts: [], config: {:fields, [:name, :price]}},
%{tag: :index, state: :end}

]

iex> build_default_layout_paths([], "product", %{fields: [%{field: :name}, %{field: :price}]}, [], :form) [

%{tag: :form, state: :start, config: {:name, "product"}, opts: []},
%{tag: :inline, state: :start, config: {:fields, [:name, :price]}, opts: []},
%{tag: :inline, state: :end},
%{tag: :form, state: :end}

]

edit_layout(name, opts, do_block \\ nil)

(macro)
@spec edit_layout(atom(), keyword(), any()) :: Macro.t()

Defines a form layout for resource editing.

Parameters

  • name (atom()): Resource configuration name.
  • opts (keyword(), optional): Additional layout options. See below for supported options.
  • do_block (optional): Layout definition block.

Options

See Aurora.Uix.Layout.Options.Form for all supported options and behaviors.

  • :edit_title (binary() | (map() -> Phoenix.LiveView.Rendered.t())): The title for the edit form. Default: "Edit {name}", where {name} is the capitalized schema name.

  • :edit_subtitle (binary() | (map() -> Phoenix.LiveView.Rendered.t())): The subtitle for the edit form. Default: "Use this form to manage <strong>{title}</strong> records in your database", where {title} is the capitalized table name.

  • :new_title (binary() | (map() -> Phoenix.LiveView.Rendered.t())): The title for the new resource form. Default: "New {name}", where {name} is the capitalized schema name.

  • :new_subtitle (binary() | (map() -> Phoenix.LiveView.Rendered.t())): The subtitle for the new resource form. Default: "Creates a new <strong>{name}</strong> record in your database", where {name} is the capitalized schema name.

Actions

The following actions are available (see Aurora.Uix.Templates.Basic.Actions.Index for details and usage):

  • add_row_action: {name, &fun/1}: Adds a row action at the end.
  • insert_row_action: {name, &fun/1}: Inserts a row action at a specific position.
  • replace_row_action: {name, &fun/1}: Replaces a row action by name.
  • remove_row_action: name: Removes a row action by name (e.g., :default_row_edit).
  • add_header_action: {name, &fun/1}: Adds a header action at the end.
  • insert_header_action: {name, &fun/1}: Inserts a header action at a specific position.
  • replace_header_action: {name, &fun/1}: Replaces a header action by name.
  • remove_header_action: name: Removes a header action by name (e.g., :default_new).

Behavior

  • Renders an editable form layout for the resource.
  • Options allow customization of form titles, subtitles, and field arrangement.

Example

edit_layout :product, edit_title: "Edit Product" do
  inline [:reference, :name, :description]
end

group(title, opts, do_block \\ nil)

(macro)
@spec group(atom(), keyword(), any()) :: Macro.t()

Defines a group sub-layout to visually segment related fields under a common title.

Parameters

  • title (string()): The title of the group.
  • opts (keyword()): Additional options for the group layout.
  • block: An optional do block containing nested layout definitions.

Example

  group "Identification", [:reference, :name, :description]

index_columns(name, fields, do_block \\ nil)

(macro)
@spec index_columns(atom(), keyword() | list(), any()) :: Macro.t()

Registers index columns and associated options for a specific resource.

Parameters

  • name (atom): Resource configuration name.
  • fields (list | keyword): List of field atoms or field/option pairs to display as columns.

  • do_block (optional): Optional block for nested layout or further customization.

Options

  • :pagination_disabled? (boolean()) - If true, pagination is not used for populating the index list.
  • :page_title (binary() | (map() - Phoenix.LiveView.Rendered.t())): The page title for the index layout. Example: page_title: "Products List" or page_title: &custom_page_title/1.

  • :page_subtitle (binary() | (map() - Phoenix.LiveView.Rendered.t())): The page subtitle for the index layout. Example: page_subtitle: "All available products" or page_subtitle: &custom_page_subtitle/1.

  • :order_by (atom() | list() | keyword()) - Order used for displaying the index. Takes precedence over any order_by set in auix_resource_metadata. See Aurora.Uix.Layout.ResourceMetadata.auix_resource_metadata/3 for details.

  • :where (keyword()) - Where clauses to use for filtering the items to show.
  • Field-level options can be provided as keyword lists for each field (e.g., [name: [renderer: &custom_renderer/1]]).

Field-level Options

Besides the metadata options, there are some field types that can accept specific options for changing the way they are rendered.

Fields representing one-to-many association.

  • :order_by (atom() | list() | keyword()) - Order by used for displaying the related items. Uses the same criteria as the order_by option described above.

  • :where (list()) - Allows filtering the rendered options.

Those are the fields that referred the id that associates the many to one relation. For example: product_id. They are, by default, represented as a select html type.

  • :option_label (atom() | function()) - The label to be shown for each option. Can be:

    • atom() - Renders the field contents.
    • function/1 - Receives the entity as an argument, must return a Phoenix.LiveView.Rendered.t()
    • function/2 - Receives assigns and the entity as arguments, expected to return Phoenix.LiveView.Rendered.t()

Actions

The following actions are available (see Aurora.Uix.Templates.Basic.Actions.Index for details and usage):

  • add_row_action: {name, &fun/1}: Adds a row action at the end.
  • insert_row_action: {name, &fun/1}: Inserts a row action at a specific position.
  • replace_row_action: {name, &fun/1}: Replaces a row action by name.
  • remove_row_action: name: Removes a row action by name (e.g., :default_row_edit).
  • add_header_action: {name, &fun/1}: Adds a header action at the end.
  • insert_header_action: {name, &fun/1}: Inserts a header action at a specific position.
  • replace_header_action: {name, &fun/1}: Replaces a header action by name.
  • remove_header_action: name: Removes a header action by name (e.g., :default_new).

Note: Row-related actions (such as add_row_action, insert_row_action, replace_row_action, remove_row_action) will receive an @auix.row_info assign containing a tuple {id, row_entity} for the current row.

Behavior

  • Fields listed in fields will be rendered as columns in the index table.
  • Options and actions allow customization of the index page title, subtitle, and available actions.

Examples

# Basic usage with default actions and titles
index_columns :product, [:name, :price]

# Custom page title and subtitle
index_columns :product, [:name, :price],
  page_title: "Products List",
  page_subtitle: "All available products"

# Add a custom row action and remove the default delete action
defmodule MyApp.Actions do
  def custom_action(assigns) do
    ~H"<.link navigate={~p"/edit_page"}"
  end
end
index_columns :product, [:name, :price],
  add_row_action: {:custom, &MyApp.Actions.custom_action/1},
  remove_row_action: :default_row_delete

inline(fields, do_block \\ nil)

(macro)
@spec inline(
  keyword(),
  any()
) :: Macro.t()

Defines an inline sub-layout that groups fields horizontally within a form or show container.

This macro accepts a list of fields (or UI override options) and an optional do block for defining nested layouts. It is used to arrange fields side-by-side, either as a standalone block or as part of a larger layout.

Parameters

  • fields (list()): A list of field identifiers or keyword options for field-specific UI customizations.
  • block: An optional do block containing nested layout definitions.

Examples

Inline without a nested block:

  inline [:reference, :name, :description]

Inline with nested sub-layouts:

  inline do
    group "Basic Info" do
      inline [:reference, :name]
      stacked [:description, :notes]
    end
  end

parse_sections(layout_tree, layout_type)

@spec parse_sections(Aurora.Uix.TreePath.t(), atom()) :: Aurora.Uix.TreePath.t()

Parses a list of paths to handle sections based on the given layout type.

Parameters

  • paths (list()): A list of layout_tree maps representing the layout structure.
  • layout_type (atom()): The layout type of parsing, such as :index or other modes.

Returns

  • list(): A list of parsed paths with sections processed according to the layout type.

Examples

iex> paths = [

%{tag: :sections, state: :start},
%{tag: :section, state: :start, config: [tab_id: "tab1", label: "Tab 1"], opts: []},
%{tag: :section, state: :end},
%{tag: :sections, state: :end}
]

iex> parse_sections(paths, :form) [

%{
  tag: :sections,
  state: :start,
  config: [%{active: true, label: "Tab 1", tab_id: "tab1"}]
},
%{
  tag: :section,
  state: :start,
  config: [active: true, tab_id: "tab1", label: "Tab 1"],
  opts: []
},
%{tag: :section, state: :end},
%{tag: :sections, state: :end}

]

section(label, opts, do_block \\ nil)

(macro)
@spec section(binary(), keyword(), any()) :: Macro.t()

Defines a section within a sections container, representing a tab that contains a specific set of fields.

Parameters

  • label (string()): The label for the section.
  • opts (keyword()): Additional options for the section layout.
  • block: An optional do block for nested layout definitions.

Example

  section "Details", [:reference, :name, :description]

sections(opts, do_block \\ nil)

(macro)
@spec sections(
  keyword(),
  any()
) :: Macro.t()

Defines a sections container that groups multiple section entries into tab-like structures.

Parameters

  • opts (keyword()): Additional options for configuring the sections container.
  • block: A do block containing one or more section definitions.

Example

  sections do
    section "Details", [:reference, :name]
    section "Prices", [:msrp, :rrp]
  end

show_layout(name, opts, do_block \\ nil)

(macro)
@spec show_layout(atom(), keyword(), any()) :: Macro.t()

Defines a read-only layout for resource display.

Parameters

  • name (atom()): Resource configuration name.
  • opts (keyword(), optional): Options for customizing the show layout. See below for supported options.
  • do_block (optional): Layout definition block.

Options

See Aurora.Uix.Layout.Options.Page for all supported options and behaviors.

  • :page_title (binary() | (map() -> Phoenix.LiveView.Rendered.t())): The page title for the show layout. Default: "{name}".

  • :page_subtitle (binary() | (map() -> Phoenix.LiveView.Rendered.t())): The page subtitle for the show layout. Default: "Details".

Actions

The following actions are available (see Aurora.Uix.Templates.Basic.Actions.Index for details and usage):

  • add_row_action: {name, &fun/1}: Adds a row action at the end.
  • insert_row_action: {name, &fun/1}: Inserts a row action at a specific position.
  • replace_row_action: {name, &fun/1}: Replaces a row action by name.
  • remove_row_action: name: Removes a row action by name (e.g., :default_row_edit).
  • add_header_action: {name, &fun/1}: Adds a header action at the end.
  • insert_header_action: {name, &fun/1}: Inserts a header action at a specific position.
  • replace_header_action: {name, &fun/1}: Replaces a header action by name.
  • remove_header_action: name: Removes a header action by name (e.g., :default_new).

Behavior

  • Renders fields in a disabled/read-only state.
  • All options are processed only for the :show tag.

Examples

show_layout :product, page_title: "Product Details" do
  inline [:reference, :name, :description]
end

def page_title(assigns), do: ~H"Details for {@auix.name}"
show_layout :product, page_title: &page_title/1,
                        page_subtitle: "Extra Info" do
  inline [:reference, :name, :description]
end

stacked(fields, do_block \\ nil)

(macro)
@spec stacked(
  keyword(),
  any()
) :: Macro.t()

Defines a stacked sub-layout that groups fields vertically within a form or show container.

This macro accepts a list of fields (or UI override options) and an optional do block for further nesting. It is typically used to arrange fields one below the other, creating a vertical grouping that aids in visual organization.

Parameters

  • fields (list()): A list of field identifiers or keyword options for UI customizations.
  • block: An optional do block containing nested layout definitions.

Example

  stacked [:quantity_initial, :quantity_entries, :quantity_exits, :quantity_at_hand]