improve table component

This commit is contained in:
shibao 2023-02-26 00:37:01 -05:00
parent b1d442ea88
commit 0eafb54266
2 changed files with 54 additions and 26 deletions

View File

@ -6,7 +6,7 @@ defmodule LokalWeb.Components.TableComponent do
- `:columns`: An array of maps containing the following keys - `:columns`: An array of maps containing the following keys
- `:label`: A gettext'd or otherwise user-facing string label for the - `:label`: A gettext'd or otherwise user-facing string label for the
column. Can be nil column. Can be nil
- `:key`: A string key used for sorting - `:key`: An atom key used for sorting
- `:class`: Extra classes to be applied to the column element, if desired. - `:class`: Extra classes to be applied to the column element, if desired.
Optional Optional
- `:sortable`: If false, will prevent the user from sorting with it. - `:sortable`: If false, will prevent the user from sorting with it.
@ -21,6 +21,7 @@ defmodule LokalWeb.Components.TableComponent do
use LokalWeb, :live_component use LokalWeb, :live_component
alias Phoenix.LiveView.Socket alias Phoenix.LiveView.Socket
require Integer
@impl true @impl true
@spec update( @spec update(
@ -28,26 +29,50 @@ defmodule LokalWeb.Components.TableComponent do
required(:columns) => required(:columns) =>
list(%{ list(%{
required(:label) => String.t() | nil, required(:label) => String.t() | nil,
required(:key) => String.t() | nil, required(:key) => atom() | nil,
optional(:class) => String.t(), optional(:class) => String.t(),
optional(:row_class) => String.t(),
optional(:alternate_row_class) => String.t(),
optional(:sortable) => false optional(:sortable) => false
}), }),
required(:rows) => required(:rows) =>
list(%{ list(%{
(key :: String.t()) => any() | {custom_sort_value :: String.t(), value :: any()} (key :: atom()) => any() | {custom_sort_value :: String.t(), value :: any()}
}), }),
optional(:inital_key) => atom(),
optional(:initial_sort_mode) => atom(),
optional(any()) => any() optional(any()) => any()
}, },
Socket.t() Socket.t()
) :: {:ok, Socket.t()} ) :: {:ok, Socket.t()}
def update(%{columns: columns, rows: rows} = assigns, socket) do def update(%{columns: columns, rows: rows} = assigns, socket) do
initial_key = columns |> List.first() |> Map.get(:key) initial_key =
rows = rows |> Enum.sort_by(fn row -> row |> Map.get(initial_key) end, :asc) if assigns |> Map.has_key?(:initial_key) do
assigns.initial_key
else
columns |> List.first(%{}) |> Map.get(:key)
end
initial_sort_mode =
if assigns |> Map.has_key?(:initial_sort_mode) do
assigns.initial_sort_mode
else
:asc
end
rows = rows |> sort_by_custom_sort_value_or_value(initial_key, initial_sort_mode)
socket = socket =
socket socket
|> assign(assigns) |> assign(assigns)
|> assign(columns: columns, rows: rows, last_sort_key: initial_key, sort_mode: :asc) |> assign(
columns: columns,
rows: rows,
last_sort_key: initial_key,
sort_mode: initial_sort_mode
)
|> assign_new(:row_class, fn -> "bg-white" end)
|> assign_new(:alternate_row_class, fn -> "bg-gray-200" end)
{:ok, socket} {:ok, socket}
end end
@ -56,20 +81,19 @@ defmodule LokalWeb.Components.TableComponent do
def handle_event( def handle_event(
"sort_by", "sort_by",
%{"sort-key" => key}, %{"sort-key" => key},
%{assigns: %{rows: rows, last_sort_key: key, sort_mode: sort_mode}} = socket %{assigns: %{rows: rows, last_sort_key: last_sort_key, sort_mode: sort_mode}} = socket
) do ) do
sort_mode = if sort_mode == :asc, do: :desc, else: :asc key = key |> String.to_existing_atom()
rows = rows |> sort_by_custom_sort_value_or_value(key, sort_mode)
{:noreply, socket |> assign(sort_mode: sort_mode, rows: rows)} sort_mode =
case {key, sort_mode} do
{^last_sort_key, :asc} -> :desc
{^last_sort_key, :desc} -> :asc
{_new_sort_key, _last_sort_mode} -> :asc
end end
def handle_event( rows = rows |> sort_by_custom_sort_value_or_value(key, sort_mode)
"sort_by", {:noreply, socket |> assign(last_sort_key: key, sort_mode: sort_mode, rows: rows)}
%{"sort-key" => key},
%{assigns: %{rows: rows}} = socket
) do
rows = rows |> sort_by_custom_sort_value_or_value(key, :asc)
{:noreply, socket |> assign(last_sort_key: key, sort_mode: :asc, rows: rows)}
end end
defp sort_by_custom_sort_value_or_value(rows, key, sort_mode) do defp sort_by_custom_sort_value_or_value(rows, key, sort_mode) do

View File

@ -1,4 +1,4 @@
<div class="w-full overflow-x-auto border border-gray-600 rounded-lg shadow-lg bg-black"> <div id={@id} class="w-full overflow-x-auto border border-gray-600 rounded-lg shadow-lg bg-white">
<table class="min-w-full table-auto text-center bg-white"> <table class="min-w-full table-auto text-center bg-white">
<thead class="border-b border-primary-600"> <thead class="border-b border-primary-600">
<tr> <tr>
@ -6,26 +6,27 @@
<%= if column |> Map.get(:sortable, true) do %> <%= if column |> Map.get(:sortable, true) do %>
<th class={["p-2", column[:class]]}> <th class={["p-2", column[:class]]}>
<span <span
class="cursor-pointer" class="cursor-pointer flex justify-center items-center space-x-2"
phx-click="sort_by" phx-click="sort_by"
phx-value-sort-key={key} phx-value-sort-key={key}
phx-target={@myself} phx-target={@myself}
> >
<span class="underline"><%= label %></span> <i class="w-0 float-right fas fa-sm fa-chevron-up opacity-0"></i>
<span class={if @last_sort_key == key, do: "underline"}><%= label %></span>
<%= if @last_sort_key == key do %> <%= if @last_sort_key == key do %>
<%= case @sort_mode do %> <%= case @sort_mode do %>
<% :asc -> %> <% :asc -> %>
<i class="fas fa-sm fa-chevron-down"></i> <i class="w-0 float-right fas fa-sm fa-chevron-down"></i>
<% :desc -> %> <% :desc -> %>
<i class="fas fa-sm fa-chevron-up"></i> <i class="w-0 float-right fas fa-sm fa-chevron-up"></i>
<% end %> <% end %>
<% else %> <% else %>
<i class="fas fa-sm fa-chevron-up opacity-0"></i> <i class="w-0 float-right fas fa-sm fa-chevron-up opacity-0"></i>
<% end %> <% end %>
</span> </span>
</th> </th>
<% else %> <% else %>
<th class={["p-2", column[:class]]}> <th class={["p-2 cursor-not-allowed", column[:class]]}>
<%= label %> <%= label %>
</th> </th>
<% end %> <% end %>
@ -33,7 +34,10 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr :for={values <- @rows}> <tr
:for={{values, i} <- @rows |> Enum.with_index()}
class={if i |> Integer.is_even(), do: @row_class, else: @alternate_row_class}
>
<td :for={%{key: key} = value <- @columns} class={["p-2", value[:class]]}> <td :for={%{key: key} = value <- @columns} class={["p-2", value[:class]]}>
<%= case values |> Map.get(key) do %> <%= case values |> Map.get(key) do %>
<% {_custom_sort_value, value} -> %> <% {_custom_sort_value, value} -> %>