defmodule SigmaKit.Components.Table do use Phoenix.LiveComponent import SigmaKit.Components.Icons, only: [icon: 1] import SigmaKit.Components.Buttons, only: [action_dropdown: 1] @doc """ Renders a table with generic 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, doc: "the unique id of the table" attr :rows, :list, required: true, doc: "A list of row data to render" 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 :alternate, :boolean, default: false, doc: "whether to alternate row colors" attr :paginate, :boolean, default: false, doc: "whether to show pagination" attr :page_number, :integer, doc: "the current page number" attr :total_pages, :integer, doc: "the total number of pages" attr :page_size, :integer, doc: "the number of rows per page" attr :total_entries, :integer, doc: "the total number of entries" 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, doc: "A column to render for the table" do attr :label, :string, doc: "The label for the column header" attr :shrink, :boolean, doc: "Whether to shrink the column to fit the content" attr :expand, :boolean, doc: "Whether to expand the column to fit the content" attr :class, :any, doc: "Additional CSS classes that can be added to column cells" end slot :action, doc: "An action item to present in a dropdown menu" do attr :label, :string, doc: "The label for the menu item" attr :event, :any, doc: "The phx-click event for the menu item" attr :target, :string, doc: "The phx-target for the menu item" attr :icon, :string, doc: "The icon for the menu item" attr :divider, :boolean, doc: "Whether to this item is a divider" end def table(%{rows: %Scrivener.Page{}} = assigns) do assigns |> assign(rows: assigns.rows.entries) |> assign(page_number: assigns.rows.page_number) |> assign(total_pages: assigns.rows.total_pages) |> assign(total_entries: assigns.rows.total_entries) |> assign(page_size: assigns.rows.page_size) |> assign(paginate: true) |> table() end def table(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))}
<.action_dropdown id={"actions-#{@id}-#{(@row_id && @row_id.(row)) || row_idx}"} class={[ "text-black rounded", @row_click && "group-hover:bg-primary-100" ]} > <:action :for={action <- @action} label={action[:label]} icon={action[:icon]} event={row_click(row, action[:event])} target={action[:target]} divider={action[:divider]} value_id={row.id} />
1} class="px-2 pt-6 mt-4 border-t border-gray-400" id={"#{@id}-pager"} > <.pagination id={@id} page_number={@page_number} total_pages={@total_pages} page_size={@page_size} total_entries={@total_entries} />
<.icon name="hero-information-circle" class="h-12 w-12 text-zinc-400" />

No Data Available

""" end defp row_click(row, v) when is_function(v), do: v.(row) defp row_click(_row, v), do: v attr :id, :any, default: nil attr :page_number, :integer, default: 1 attr :total_pages, :integer, required: true attr :page_size, :integer, required: true attr :total_entries, :integer, required: true def pagination(assigns) do ~H"""
""" end defp page_button_range(n, _max) when n <= 3, do: [1, 2, 3, 4, 5] defp page_button_range(n, max) when n >= max - 2, do: [max - 4, max - 3, max - 2, max - 1, max] defp page_button_range(n, _max) when n >= 4, do: [n - 2, n - 1, n, n + 1, n + 2] end