feat: sticky memberstable header
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
carla 2026-02-25 14:16:43 +01:00
parent 49fd2181a7
commit e5a6003ace
8 changed files with 411 additions and 324 deletions

View file

@ -715,6 +715,11 @@ defmodule MvWeb.CoreComponents do
attr :sort_field, :any, default: nil, doc: "current sort field"
attr :sort_order, :atom, default: nil, doc: "current sort order"
attr :sticky_header, :boolean,
default: false,
doc:
"when true, thead th get lg:sticky lg:top-0 bg-base-100 z-10 for use inside a scroll container on desktop"
slot :col, required: true do
attr :label, :string
attr :class, :string
@ -745,12 +750,12 @@ defmodule MvWeb.CoreComponents do
<tr>
<th
:for={col <- @col}
class={Map.get(col, :class)}
class={table_th_class(col, @sticky_header)}
aria-sort={table_th_aria_sort(col, @sort_field, @sort_order)}
>
{col[:label]}
</th>
<th :for={dyn_col <- @dynamic_cols}>
<th :for={dyn_col <- @dynamic_cols} class={table_th_sticky_class(@sticky_header)}>
<.live_component
module={MvWeb.Components.SortHeaderComponent}
id={:"sort_custom_field_#{dyn_col[:custom_field].id}"}
@ -760,7 +765,7 @@ defmodule MvWeb.CoreComponents do
sort_order={@sort_order}
/>
</th>
<th :if={@action != []}>
<th :if={@action != []} class={table_th_sticky_class(@sticky_header)}>
<span class="sr-only">{gettext("Actions")}</span>
</th>
</tr>
@ -891,6 +896,18 @@ defmodule MvWeb.CoreComponents do
end
end
# Combines column class with optional sticky header classes (desktop only; theme-friendly bg).
defp table_th_class(col, sticky_header) do
base = Map.get(col, :class)
sticky = if sticky_header, do: "lg:sticky lg:top-0 bg-base-100 z-10", else: nil
[base, sticky] |> Enum.filter(& &1) |> Enum.join(" ")
end
defp table_th_sticky_class(true),
do: "lg:sticky lg:top-0 bg-base-100 z-10"
defp table_th_sticky_class(_), do: nil
@doc """
Renders a data list.