defmodule Observer.Web.Components.Core do @moduledoc """ Provides core UI components. """ use Observer.Web, :html alias Phoenix.HTML.Form @doc ~S""" Renders a table with generic metric log styling. ## Examples <.table_tracing id="users" rows={@users}> <:col :let={user} label="id"><%= user.id %> <:col :let={user} label="username"><%= user.username %> """ attr :id, :string, required: true attr :rows, :list, required: true attr :row_id, :any, default: nil, doc: "the function for generating the row id" attr :row_click, :any, default: nil, doc: "the function for handling phx-click on each row" attr :transition, :boolean, default: false attr :row_item, :any, default: &Function.identity/1, doc: "the function for mapping each row before calling the :col slots" slot :col, required: true do attr :label, :string end def table_tracing(assigns) do assigns = with %{rows: %Phoenix.LiveView.LiveStream{}} <- assigns do assign(assigns, row_id: assigns.row_id || fn {id, _item} -> id end) end ~H"""
{col[:label]}
{render_slot(col, @row_item.(row))}
""" end @doc ~S""" Renders a table with process styling. ## Examples <.table id="users" rows={@users}> <:col :let={user} label="id"><%= user.id %> <:col :let={user} label="username"><%= user.username %> """ attr :id, :string, required: true attr :title, :string, required: true attr :rows, :list, required: true attr :row_id, :any, default: nil, doc: "the function for generating the row id" attr :row_click, :any, default: nil, doc: "the function for handling phx-click on each row" attr :transition, :boolean, default: false attr :title_bg_color, :string, default: "standard" attr :row_item, :any, default: &Function.identity/1, doc: "the function for mapping each row before calling the :col slots" slot :col, required: true do attr :label, :string end def table_process(assigns) do assigns = with %{rows: %Phoenix.LiveView.LiveStream{}} <- assigns do assign(assigns, row_id: assigns.row_id || fn {id, _item} -> id end) end ~H"""
{@title}
{render_slot(col, @row_item.(row))}
""" end defp title_bg_color("liveview"), do: "bg-green-200 dark:bg-green-900" defp title_bg_color(_any), do: "bg-zinc-200 dark:bg-zinc-500" @doc ~S""" Renders a table with generic metrics styling. ## Examples <.table id="users" rows={@users}> <:col :let={user} label="id"><%= user.id %> <:col :let={user} label="username"><%= user.username %> """ attr :id, :string, required: true attr :rows, :list, required: true attr :row_id, :any, default: nil, doc: "the function for generating the row id" attr :row_click, :any, default: nil, doc: "the function for handling phx-click on each row" attr :transition, :boolean, default: false attr :h_max_size, :string, default: "h-64" attr :row_item, :any, default: &Function.identity/1, doc: "the function for mapping each row before calling the :col and :action slots" slot :col, required: true do attr :label, :string end def table_metrics(assigns) do assigns = with %{rows: %Phoenix.LiveView.LiveStream{}} <- assigns do assign(assigns, row_id: assigns.row_id || fn {id, _item} -> id end) end ~H"""
{col[:label]}
{render_slot(col, @row_item.(row))}
""" end @doc """ Renders an input with label and error messages. A `Phoenix.HTML.FormField` may be passed as argument, which is used to retrieve the input name, id, and values. Otherwise all attributes may be passed explicitly. ## Types This function accepts all HTML input types, considering that: * You may also set `type="select"` to render a ` {@label} """ end def input(%{type: "select"} = assigns) do ~H"""
<.label for={@id}>{@label}
""" end def input(%{type: "select-undefined-class"} = assigns) do ~H"""
<.label for={@id}>{@label}
""" end def input(%{type: "textarea"} = assigns) do ~H"""
<.label for={@id}>{@label}
""" end def input(%{type: "text-custom-search"} = assigns) do ~H"""
<.label for={@id}>{@label}
""" end # All other inputs text, datetime-local, url, password, etc. are handled here... def input(assigns) do ~H"""
<.label for={@id}>{@label}
""" end @doc """ Translates an error message using gettext. """ def translate_error({msg, _opts}) do msg end @doc """ Translates the errors for a field from a keyword list of errors. """ def translate_errors(errors, field) when is_list(errors) do for {^field, {msg, opts}} <- errors, do: translate_error({msg, opts}) end @doc """ Renders a label. """ attr :for, :string, default: nil slot :inner_block, required: true def label(assigns) do ~H""" """ end @doc """ Renders a tooltip around a given inner element. ## Assigns * `:label` - The text to show inside the tooltip. * `:position` - Optional, one of `:top`, `:bottom`, `:left`, `:right`. Defaults to `:top`. """ attr :label, :string, required: true attr :position, :atom, default: :bottom slot :inner_block, required: true def tooltip(assigns) do ~H"""
{render_slot(@inner_block)}
" hidden group-hover:flex opacity-0 group-hover:opacity-100 transition-opacity duration-150 bg-white dark:bg-gray-600 text-gray-800 dark:text-gray-200 text-xs rounded py-1 px-2 z-50 max-w-[90vw] text-left whitespace-pre-line break-words" }> {@label}
""" end # Helper to handle tooltip positioning defp tooltip_position_class(:top), do: "absolute bottom-full left-1/2 -translate-x-1/2 mb-2" defp tooltip_position_class(:bottom), do: "absolute top-full left-1/2 -translate-x-1/2 mt-2" defp tooltip_position_class(:left), do: "absolute right-full top-1/2 -translate-y-1/2 mr-2" defp tooltip_position_class(:right), do: "absolute left-full top-1/2 -translate-y-1/2 ml-2" end