defmodule ToweropsWeb.Layouts do @moduledoc """ This module holds layouts and related functionality used by your application. """ use ToweropsWeb, :html # Embed all files in layouts/* within this module. # The default root.html.heex file contains the HTML # skeleton of your application, namely HTML headers # and other static content. embed_templates "layouts/*" @doc """ Renders your app layout. This function is typically invoked from every template, and it often contains your application menu, sidebar, or similar. ## Examples

Content

""" attr :flash, :map, required: true, doc: "the map of flash messages" attr :current_scope, :map, default: nil, doc: "the current [scope](https://hexdocs.pm/phoenix/scopes.html)" attr :timezone, :string, default: "UTC", doc: "the user's timezone" slot :inner_block, required: true def app(assigns) do ~H"""
{render_slot(@inner_block)}
<.footer timezone={Map.get(assigns, :timezone, "UTC")} />
<.flash_group flash={@flash} /> """ end @doc """ Renders the authenticated app layout with navigation. Use this for pages that require organization context. ## Examples

Content

""" attr :flash, :map, required: true, doc: "the map of flash messages" attr :current_scope, :map, default: nil, doc: "the current scope (contains user and impersonation state)" attr :current_organization, :any, default: nil, doc: "the current organization (can be nil for pages without org context)" attr :active_page, :string, default: nil, doc: "the currently active page (dashboard, sites, device, or alerts)" attr :timezone, :string, default: "UTC", doc: "the user's timezone" slot :inner_block, required: true def authenticated(assigns) do ~H"""
<%= if @current_scope && @current_scope.impersonating? do %>
<.icon name="hero-exclamation-triangle" class="w-5 h-5" /> Impersonating: {@current_scope.user.email}
<.link href={~p"/admin/impersonate"} method="delete" class="px-3 py-1 bg-white text-yellow-900 hover:bg-yellow-50 rounded font-medium text-sm" > Exit
<% end %>
{render_slot(@inner_block)}
<.footer timezone={Map.get(assigns, :timezone, "UTC")} />
<.flash_group flash={@flash} /> """ end attr :navigate, :string, required: true attr :active, :boolean, default: false slot :inner_block, required: true defp nav_link(assigns) do ~H""" <.link navigate={@navigate} class={[ "inline-flex items-center border-b-2 px-1 pt-1 pb-4 text-sm font-medium", if(@active, do: "border-gray-900 text-gray-900 dark:border-white dark:text-white", else: "border-transparent text-gray-700 hover:border-gray-300 hover:text-gray-900 dark:text-gray-300 dark:hover:border-gray-600 dark:hover:text-white" ) ]} > {render_slot(@inner_block)} """ end attr :navigate, :string, required: true attr :active, :boolean, default: false slot :inner_block, required: true defp mobile_nav_link(assigns) do ~H""" <.link navigate={@navigate} class={[ "flex items-center gap-3 rounded-md px-3 py-2 text-base font-medium", if(@active, do: "bg-gray-100 text-gray-900 dark:bg-gray-800 dark:text-white", else: "text-gray-600 hover:bg-gray-50 hover:text-gray-900 dark:text-gray-300 dark:hover:bg-gray-800 dark:hover:text-white" ) ]} > {render_slot(@inner_block)} """ end @doc """ Shows the flash group with standard titles and content. ## Examples <.flash_group flash={@flash} /> """ attr :flash, :map, required: true, doc: "the map of flash messages" attr :id, :string, default: "flash-group", doc: "the optional id of flash container" def flash_group(assigns) do ~H"""
<.flash kind={:info} flash={@flash} /> <.flash kind={:error} flash={@flash} /> <.flash id="client-error" kind={:error} title={gettext("We can't find the internet")} phx-disconnected={show(".phx-client-error #client-error") |> JS.remove_attribute("hidden")} phx-connected={hide("#client-error") |> JS.set_attribute({"hidden", ""})} hidden > {gettext("Attempting to reconnect")} <.icon name="hero-arrow-path" class="ml-1 size-3 motion-safe:animate-spin" /> <.flash id="server-error" kind={:error} title={gettext("Something went wrong!")} phx-disconnected={show(".phx-server-error #server-error") |> JS.remove_attribute("hidden")} phx-connected={hide("#server-error") |> JS.set_attribute({"hidden", ""})} hidden > {gettext("Attempting to reconnect")} <.icon name="hero-arrow-path" class="ml-1 size-3 motion-safe:animate-spin" />
""" end @doc """ Provides dark vs light theme toggle based on themes defined in app.css. See in root.html.heex which applies the theme before page load. """ def theme_toggle(assigns) do ~H"""
""" end @doc """ Renders the admin layout. Use this for admin pages that require superuser access. ## Examples

Admin Content

""" attr :flash, :map, required: true, doc: "the map of flash messages" attr :timezone, :string, default: "UTC", doc: "the user's timezone" slot :inner_block, required: true def admin(assigns) do ~H"""
{render_slot(@inner_block)}
<.footer timezone={Map.get(assigns, :timezone, "UTC")} />
<.flash_group flash={@flash} /> """ end @doc """ Renders the application footer with copyright notice and deploy timestamp. """ attr :timezone, :string, default: "UTC" def footer(assigns) do alias ToweropsWeb.TimeHelpers build_time = Towerops.Application.build_timestamp() timezone = Map.get(assigns, :timezone, "UTC") assigns = assigns |> assign(:build_time, build_time) |> assign(:time_ago, TimeHelpers.format_time_ago(build_time)) |> assign(:formatted_time, TimeHelpers.format_iso8601(build_time, timezone)) ~H""" """ end end