Comment on page
📄
Layouts & Menus
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.
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, you can simply duplicate the layout file from the petal_framework library into your
/components
directory and change the module name. How to do that?Firstly, let's take a look at all the components in Petal Framework. While in your project directory, run this command:
# this assumes you're using vscode:
code deps/petal_framework/lib/petal_framework/web/components
This will open a new VSCode instance with all the Petal Framework components. Here you can see the
sidebar_layout.ex
file.
- 1.Copy
sidebar_layout.ex
to<your_app>_web/components/
- 2.Change the module name from
PetalFramework.Components.SidebarLayout
toYourAppWeb.Components.SidebarLayout
- 3.In
core_components.ex
add animport
statement to import your module, e.g.import YourAppWeb.Components.SidebarLayout
- 4.You will notice that due to the existing
use PetalFramework
the application would no longer compile correctly, simply rename the function in your new layout, e.g. fromsidebar_layout
tomyapp_sidebar_layout
- 5.Go back to
core_components.ex
and renamesidebar_layout
tomyapp_sidebar_layout
- 6.Now when you call
<.layout type="sidebar">
it will render your duplicate layout instead, and you can modify it to however you like
- 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 inlayout.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 thelayout/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>
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>

Sidebar layout in action

Sidebar layout on mobile (closed)

Sidebar layout on mobile (open)
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

Stacked layout

Stacked layout on mobile

Stacked layout on mobile with menu open
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>

Light mode

Dark mode
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
:
How layouts use menu lists
Last modified 6mo ago