defmodule TarakanWeb.CurrentPath do @moduledoc """ Makes the request path available to the layout as `@current_path`. The navigation highlight used to be applied by JavaScript after render, which had two problems. Every page painted with nothing highlighted and lit up a frame later, and dead controller routes like `/pricing` have no LiveSocket at all, so the hook never ran there and the tab could never highlight itself. Both go away if the server decides. This supplies the path for the two kinds of page: a plug for controller-rendered views, and an `on_mount` hook that re-reads it on every `handle_params` so live navigation stays correct. """ import Phoenix.Component, only: [assign: 3] import Phoenix.LiveView, only: [attach_hook: 4] @doc "Plug for controller-rendered pages." def init(opts), do: opts def call(conn, _opts), do: Plug.Conn.assign(conn, :current_path, conn.request_path) @doc "`on_mount` hook for live sessions." def on_mount(:default, _params, _session, socket) do {:cont, socket |> assign(:current_path, nil) |> attach_hook(:current_path, :handle_params, &put_current_path/3)} end defp put_current_path(_params, uri, socket) do {:cont, assign(socket, :current_path, URI.parse(uri).path)} end @doc """ Whether `path` is the section the visitor is currently in. A section owns its subtree, so `/jobs` stays lit on `/jobs/12`. The root is matched exactly, otherwise it would own every page on the site. """ def active?(nil, _path), do: false def active?(_current, nil), do: false def active?(current, "/"), do: current == "/" def active?(current, path) do current == path or String.starts_with?(current, path <> "/") end end