πŸ“„Layouts & Menus

The layout component

Petal Pro gives the developer a <.layout> component, which takes a type attribute and renders a layout based on that type. eg:

<.layout current_page={:dashboard} current_user={@current_user} type="sidebar">
  <.container max_width="xl">
    <div>content</div>
  </.container>
</.layout>

It works by a simple case statement:

layout.ex
...
<%= case @type do %>
  <% "sidebar" -> %>
    <.sidebar_layout {assigns}>
      ...
    </.sidebar_layout>
  <% "stacked" -> %>
    <.stacked_layout {assigns}>
      ...
    </.stacked_layout>
  <% "public" -> %>
    <.public_layout {assigns}>
      ...
    </.public_layout>
<% end %>
...

You can maintain this file and add/remove layouts as you please.

How to modify an existing layout

Petal Pro provides a number of layouts: "sidebar", "stacked" and "public". These are quite configurable however you may want to modify them. To do so, simply duplicate the layout file from the _petal_framework/web/components/layout folder into your /components directory and change the module name. eg to modify the sidebar layout:

  1. Copy sidebar_layout.ex to <your_app>_web/components/

  2. Change the module name from PetalFramework.Components.SidebarLayout to YourAppWeb.Components.SidebarLayout

  3. In layout.ex change the import statement to import your module instead of the old one.

  4. Now when you call <.layout type="sidebar"> it will render your duplicate layout instead, and you can modify it to however you like

How to add a new layout

  1. Create a new file in <you_app>_web/components , eg: my_cool_layout.ex

  2. Look at what assigns other layouts like sidebar.ex use - you can see in layout.ex how menu items are passed in, as well as the user's name and avatar

  3. When complete, you can import your layout into layout.ex and modify the layout/1 function - eg:

<%= case @type do %>
  <% "my-cool-layout" -> %>
    <.my_cool_layout {assigns}>

4. Now in your template or live view file, you simply update the type to your new layout:

<.layout type="my-cool-layout" current_page={:dashboard} current_user={@current_user}>
  <.container>
    <div>content</div>
  </.container>
</.layout>

Petal Pro Layouts

This is the typical web application layout. It allows for a large number of menu items on the sidebar.

<.layout current_page={:dashboard} current_user={@current_user} type="sidebar">
  <.container>
    <div>content</div>
  </.container>
</.layout>

Stacked layout

A stacked layout with a navbar and then content.

<.layout current_page={:dashboard} current_user={@current_user} type="stacked">
  <.container max_width="xl">
    <div>content</div>
  </.container>
</.layout>e

Public layout

Includes a header and footer - for use in public facing, marketing pages.

<.layout 
  type="public" 
  current_user={assigns[:current_user]} 
  current_page={:landing} 
  max_width="sm|md|lg|xl|full"
>

</.layout>

In menus.ex there is a list of all the menu items. This can be useful when working with navbars and layouts, where you sometimes need to loop over menu items multiple times.

For all menu items, you must define a new get_link/2 function, which takes a name and current_user as the parameters. The name parameter is pattern matched and thus you statically include it in the function definition. A menu item has a name, label, path and icon. Here's an example of a menu item for the "Register" menu item:

def get_link(:register, _current_user) do
  %{
    name: :register,
    label: "Register",
    path: Routes.user_registration_path(Endpoint, :new),
    icon: :clipboard_list
  }
end

You can use the current_user param to conditionally display a menu item. For example, here we don't show the menu item unless the user is an admin.

def get_link(:admin_users = name, current_user) do
  if Helpers.is_admin?(current_user) do
    %{
      name: name,
      label: "Users",
      path: Routes.admin_users_path(Endpoint, :index),
      icon: :users
    }
  else
    nil
  end
end

You can build menu item lists to give to layouts. We define the two core menu lists in menus.ex:

Last updated