Skip to main content

Adjusting the Layouts

The Phoenix Generator created two layouts for us:

  • layouts/root.html.heex - The Root Layout is always used. It's a good idea to keep this minimal, since it will apply to all pages.
  • layouts/app.html.heex - The application layout is used for all LiveViews.

The Root Layout

The Root Layout generates with a simple header. This header includes login, register, and user settings links. While this is a good start, we will add a branding section to the left side of the header.

Replace everything between the body tags with:

<div class="flex justify-between px-4 mt-2">
  <.link navigate={~p"/"} class="font-black">Elixir Mud</.link>
  <ul class="relative z-10 flex items-center gap-4 sm:px-6 lg:px-8 justify-end">
    <li :if={@current_player} class="text-[0.8125rem] leading-6 text-zinc-900">
      {@current_player.email}
    </li>
    <li :if={@current_player}>
      <.link
        href={~p"/players/settings"}
        class="text-[0.8rem] leading-6 text-zinc-900 font-semibold hover:text-zinc-700"
      >
        Settings
      </.link>
    </li>
    <li :if={@current_player}>
      <.link
        href={~p"/players/log_out"}
        method="delete"
        class="text-[0.8rem] leading-6 text-zinc-900 font-semibold hover:text-zinc-700"
      >
        Log out
      </.link>
    </li>
    <li :if={!@current_player}>
      <.link
        href={~p"/players/register"}
        class="text-[0.8rem] leading-6 text-zinc-900 font-semibold hover:text-zinc-700"
      >
        Register
      </.link>
    </li>
    <li :if={!@current_player}>
      <.link
        href={~p"/players/log_in"}
        class="text-[0.8rem] leading-6 text-zinc-900 font-semibold hover:text-zinc-700"
      >
        Log in
      </.link>
    </li>
  </ul>
</div>

apps/elixir_mud_web/lib/elixir_mud_web/components/layouts/root.html.heex

The Application Layout

The application layout contains some Phoenix links. We can remove those. For now replace the contents with:

<header class="px-4 sm:px-6 lg:px-8">
  <div class="flex items-center justify-between border-b border-zinc-100 py-3 text-sm">
    <div class="flex items-center gap-4">
    </div>
  </div>
</header>
<main class="px-4 py-20 sm:px-6 lg:px-8">
  <div class="mx-auto max-w-2xl">
    <.flash_group flash={@flash} />
    {@inner_content}
  </div>
</main>

apps/elixir_mud_web/lib/elixir_mud_web/components/layouts/app.html.heex

The Empty Layout

We will use the Application Layout specifically for pages inside the main web application, such as character creation and the web client. Lets implement an Empty Layout that we can use for registration, login, etc. This will keep those pages clean.

Create a new file in the layouts folder called empty.html.heex:

<main class="px-4 py-20 sm:px-6 lg:px-8">
  <div class="mx-auto max-w-2xl">
    <.flash_group flash={@flash} />
    {@inner_content}
  </div>
</main>

Modifying The Routes

Now it's time to modify routes to use the new Empty Layout. We simply need to add layout: {LayoutModule, :name} to the LiveSession. In our case that will be layout: {ElixirMudWeb.Layouts, :empty}.

First, there is a LiveSession that contains routes for registration and login:

  scope "/", ElixirMudWeb do
    pipe_through [:browser, :redirect_if_player_is_authenticated]

    live_session :redirect_if_player_is_authenticated,
      layout: {ElixirMudWeb.Layouts, :empty},
      on_mount: [{ElixirMudWeb.PlayerAuth, :redirect_if_player_is_authenticated}] do
      live "/players/register", PlayerRegistrationLive, :new
      live "/players/log_in", PlayerLoginLive, :new
      live "/players/reset_password", PlayerForgotPasswordLive, :new
      live "/players/reset_password/:token", PlayerResetPasswordLive, :edit
    end

    post "/players/log_in", PlayerSessionController, :create
  end

apps/elixir_mud_web/lib/elixir_mud_web/router.ex

Second, the LiveSession for player settings:

scope "/", ElixirMudWeb do
    pipe_through [:browser, :require_authenticated_player]

    live_session :require_authenticated_player,
      layout: {ElixirMudWeb.Layouts, :empty},
      on_mount: [{ElixirMudWeb.PlayerAuth, :ensure_authenticated}] do
      live "/players/settings", PlayerSettingsLive, :edit
      live "/players/settings/confirm_email/:token", PlayerSettingsLive, :confirm_email
    end
  end

apps/elixir_mud_web/lib/elixir_mud_web/router.ex

Lastly, the LiveSession for confirmation:

  scope "/", ElixirMudWeb do
    pipe_through [:browser]

    delete "/players/log_out", PlayerSessionController, :delete

    live_session :current_player,
      layout: {ElixirMudWeb.Layouts, :empty},
      on_mount: [{ElixirMudWeb.PlayerAuth, :mount_current_player}] do
      live "/players/confirm/:token", PlayerConfirmationLive, :edit
      live "/players/confirm", PlayerConfirmationInstructionsLive, :new
    end
  end

apps/elixir_mud_web/lib/elixir_mud_web/router.ex

Checking Tests

If we run mix test, we should see that all tests are passing. Nothing we changed is effecting any current test cases.

Updated on Jun 5, 2025