# 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:

```markup
<.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:

{% code title="layout.ex" %}

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

{% endcode %}

You can maintain this file and add/remove layouts as you please.&#x20;

### 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,  you can simply edit or duplicate the layout file in the following path:

```bash
/lib/petal_pro_web/components/pro_components 
```

Here you can see the `sidebar_layout.ex` and `stacked_layout.ex` files.

<figure><img src="https://content.gitbook.com/content/jybnmx3gX5MSuPHDwIJB/blobs/h63OAl0JXwAcrEJD67IZ/Screenshot%20from%202024-07-29%2017-26-50.png" alt=""><figcaption></figcaption></figure>

### How to add a new layout

1. Copy `<you_app>_web/components/pro_components/sidebar_layout.ex` , eg: `my_cool_layout.ex`
2. Review assigns and adjust your new layout - you can see in `layout/1` (`core_components.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 `core_componets.ex` and modify the `layout/1` function - eg:

```markup
<%= 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:

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

## Petal Pro Layouts

### Sidebar layout

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

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

![Sidebar layout in action](https://content.gitbook.com/content/jybnmx3gX5MSuPHDwIJB/blobs/JqWlxIQhxlAITFOMYSDX/Screen%20Shot%202022-03-04%20at%2012.46.34%20pm.png)

![Sidebar layout on mobile (closed)](https://content.gitbook.com/content/jybnmx3gX5MSuPHDwIJB/blobs/dA4m26x8K4xptI7nd7c6/sidebar_mobile_closed.png)

![Sidebar layout on mobile (open)](https://content.gitbook.com/content/jybnmx3gX5MSuPHDwIJB/blobs/bR6TObeIcyVsMUhi8kIe/sidebar_mobile_open.png)

### Stacked layout

A stacked layout with a navbar and then content.

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

![Stacked layout](https://content.gitbook.com/content/jybnmx3gX5MSuPHDwIJB/blobs/JicgvUpXnLrs8UVwek92/stacked_layout.png)

![Stacked layout on mobile](https://content.gitbook.com/content/jybnmx3gX5MSuPHDwIJB/blobs/GG53jMx4ozdeusgWGm4o/stacked_mobile_closed.png)

![Stacked layout on mobile with menu open](https://content.gitbook.com/content/jybnmx3gX5MSuPHDwIJB/blobs/EG6yo43uIO4dYksv0cE0/stacked_mobile_open.png)

### Public layout

Includes a header and footer - for use in public facing, marketing pages. The public layout is available in `router.ex` via the `:public_layout` pipeline:

```elixir

# Public routes
scope "/", PetalProWeb do
  pipe_through [:browser, :public_layout]

  # Add public controller routes here
  get "/", PageController, :landing_page
  get "/privacy", PageController, :privacy
  get "/license", PageController, :license

  live_session :public, layout: {PetalProWeb.Layouts, :public} do
    # Add public live routes here
  end
end
```

![Light mode](https://content.gitbook.com/content/jybnmx3gX5MSuPHDwIJB/blobs/jPgPn7ObeGbnweLI8PQU/CleanShot%202022-05-31%20at%2016.19.21.png)

![Dark mode](https://content.gitbook.com/content/jybnmx3gX5MSuPHDwIJB/blobs/u6BQ2gUXTDP9NMfNPk12/CleanShot%202022-05-31%20at%2011.06.52.png)

## Menus

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:

```elixir
def get_link(:register, _current_user) do
  %{
    name: :register,
    label: "Register",
    path: Routes.user_registration_path(Endpoint, :new),
    icon: "hero-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.

```elixir
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: "hero-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](https://content.gitbook.com/content/jybnmx3gX5MSuPHDwIJB/blobs/1o72Z7x1LmYAVvU5CIxP/Menus.png)
