add table component
This commit is contained in:
		
							
								
								
									
										87
									
								
								lib/lokal_web/components/table_component.ex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								lib/lokal_web/components/table_component.ex
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,87 @@ | ||||
| defmodule LokalWeb.Components.TableComponent do | ||||
|   @moduledoc """ | ||||
|   Livecomponent that presents a resortable table | ||||
|  | ||||
|   It takes the following required assigns: | ||||
|     - `:columns`: An array of maps containing the following keys | ||||
|       - `:label`: A gettext'd or otherwise user-facing string label for the | ||||
|         column. Can be nil | ||||
|       - `:key`: A string key used for sorting | ||||
|       - `:class`: Extra classes to be applied to the column element, if desired. | ||||
|         Optional | ||||
|       - `:sortable`: If false, will prevent the user from sorting with it. | ||||
|         Optional | ||||
|     - `:values`: An array of maps containing data for each row. Each map is | ||||
|       string-keyed with the associated column key to the following values: | ||||
|       - A single element, like string, integer or Phoenix.LiveView.Rendered | ||||
|         object, like returned from the ~H sigil | ||||
|       - A tuple, containing a custom value used for sorting, and the displayed | ||||
|         content. | ||||
|   """ | ||||
|  | ||||
|   use LokalWeb, :live_component | ||||
|   alias Phoenix.LiveView.Socket | ||||
|  | ||||
|   @impl true | ||||
|   @spec update( | ||||
|           %{ | ||||
|             required(:columns) => | ||||
|               list(%{ | ||||
|                 required(:label) => String.t() | nil, | ||||
|                 required(:key) => String.t() | nil, | ||||
|                 optional(:class) => String.t(), | ||||
|                 optional(:sortable) => false | ||||
|               }), | ||||
|             required(:rows) => | ||||
|               list(%{ | ||||
|                 (key :: String.t()) => any() | {custom_sort_value :: String.t(), value :: any()} | ||||
|               }), | ||||
|             optional(any()) => any() | ||||
|           }, | ||||
|           Socket.t() | ||||
|         ) :: {:ok, Socket.t()} | ||||
|   def update(%{columns: columns, rows: rows} = assigns, socket) do | ||||
|     initial_key = columns |> List.first() |> Map.get(:key) | ||||
|     rows = rows |> Enum.sort_by(fn row -> row |> Map.get(initial_key) end, :asc) | ||||
|  | ||||
|     socket = | ||||
|       socket | ||||
|       |> assign(assigns) | ||||
|       |> assign(columns: columns, rows: rows, last_sort_key: initial_key, sort_mode: :asc) | ||||
|  | ||||
|     {:ok, socket} | ||||
|   end | ||||
|  | ||||
|   @impl true | ||||
|   def handle_event( | ||||
|         "sort_by", | ||||
|         %{"sort-key" => key}, | ||||
|         %{assigns: %{rows: rows, last_sort_key: key, sort_mode: sort_mode}} = socket | ||||
|       ) do | ||||
|     sort_mode = if sort_mode == :asc, do: :desc, else: :asc | ||||
|     rows = rows |> sort_by_custom_sort_value_or_value(key, sort_mode) | ||||
|     {:noreply, socket |> assign(sort_mode: sort_mode, rows: rows)} | ||||
|   end | ||||
|  | ||||
|   def handle_event( | ||||
|         "sort_by", | ||||
|         %{"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 | ||||
|  | ||||
|   defp sort_by_custom_sort_value_or_value(rows, key, sort_mode) do | ||||
|     rows | ||||
|     |> Enum.sort_by( | ||||
|       fn row -> | ||||
|         case row |> Map.get(key) do | ||||
|           {custom_sort_key, _value} -> custom_sort_key | ||||
|           value -> value | ||||
|         end | ||||
|       end, | ||||
|       sort_mode | ||||
|     ) | ||||
|   end | ||||
| end | ||||
							
								
								
									
										52
									
								
								lib/lokal_web/components/table_component.html.heex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								lib/lokal_web/components/table_component.html.heex
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | ||||
| <div class="w-full overflow-x-auto border border-gray-600 rounded-lg shadow-lg bg-black"> | ||||
|   <table class="min-w-full table-auto text-center bg-white"> | ||||
|     <thead class="border-b border-primary-600"> | ||||
|       <tr> | ||||
|         <%= for %{key: key, label: label} = column <- @columns do %> | ||||
|           <%= if column |> Map.get(:sortable, true) do %> | ||||
|             <th class={"p-2 #{column[:class]}"}> | ||||
|               <span | ||||
|                 class="cursor-pointer" | ||||
|                 phx-click="sort_by" | ||||
|                 phx-value-sort-key={key} | ||||
|                 phx-target={@myself} | ||||
|               > | ||||
|                 <span class="underline"><%= label %></span> | ||||
|                 <%= if @last_sort_key == key do %> | ||||
|                   <%= case @sort_mode do %> | ||||
|                     <% :asc -> %> | ||||
|                       <i class="fas fa-sm fa-chevron-down"></i> | ||||
|                     <% :desc -> %> | ||||
|                       <i class="fas fa-sm fa-chevron-up"></i> | ||||
|                   <% end %> | ||||
|                 <% else %> | ||||
|                   <i class="fas fa-sm fa-chevron-up opacity-0"></i> | ||||
|                 <% end %> | ||||
|               </span> | ||||
|             </th> | ||||
|           <% else %> | ||||
|             <th class={"p-2 #{column[:class]}"}> | ||||
|               <%= label %> | ||||
|             </th> | ||||
|           <% end %> | ||||
|         <% end %> | ||||
|       </tr> | ||||
|     </thead> | ||||
|     <tbody> | ||||
|       <%= for values <- @rows do %> | ||||
|         <tr> | ||||
|           <%= for %{key: key} = value <- @columns do %> | ||||
|             <td class={"p-2 #{value[:class]}"}> | ||||
|               <%= case values |> Map.get(key) do %> | ||||
|                 <% {_custom_sort_value, value} -> %> | ||||
|                   <%= value %> | ||||
|                 <% value -> %> | ||||
|                   <%= value %> | ||||
|               <% end %> | ||||
|             </td> | ||||
|           <% end %> | ||||
|         </tr> | ||||
|       <% end %> | ||||
|     </tbody> | ||||
|   </table> | ||||
| </div> | ||||
		Reference in New Issue
	
	Block a user