Merge branch 'main' into feature/337_polish_import
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
This commit is contained in:
commit
3415faeb21
87 changed files with 4381 additions and 1171 deletions
|
|
@ -97,12 +97,13 @@ defmodule MvWeb.CoreComponents do
|
|||
<.button navigate={~p"/"}>Home</.button>
|
||||
<.button disabled={true}>Disabled</.button>
|
||||
"""
|
||||
attr :rest, :global, include: ~w(href navigate patch method)
|
||||
attr :rest, :global, include: ~w(href navigate patch method data-testid)
|
||||
attr :variant, :string, values: ~w(primary)
|
||||
attr :disabled, :boolean, default: false, doc: "Whether the button is disabled"
|
||||
slot :inner_block, required: true
|
||||
|
||||
def button(%{rest: rest} = assigns) do
|
||||
def button(assigns) do
|
||||
rest = assigns.rest
|
||||
variants = %{"primary" => "btn-primary", nil => "btn-primary btn-soft"}
|
||||
assigns = assign(assigns, :class, Map.fetch!(variants, assigns[:variant]))
|
||||
|
||||
|
|
@ -544,6 +545,9 @@ defmodule MvWeb.CoreComponents do
|
|||
attr :label, :string
|
||||
attr :class, :string
|
||||
attr :col_click, :any, doc: "optional column-specific click handler that overrides row_click"
|
||||
|
||||
attr :sort_field, :any,
|
||||
doc: "optional; when equal to table sort_field, aria-sort is set on this th"
|
||||
end
|
||||
|
||||
slot :action, doc: "the slot for showing user actions in the last table column"
|
||||
|
|
@ -559,7 +563,13 @@ defmodule MvWeb.CoreComponents do
|
|||
<table class="table table-zebra">
|
||||
<thead>
|
||||
<tr>
|
||||
<th :for={col <- @col} class={Map.get(col, :class)}>{col[:label]}</th>
|
||||
<th
|
||||
:for={col <- @col}
|
||||
class={Map.get(col, :class)}
|
||||
aria-sort={table_th_aria_sort(col, @sort_field, @sort_order)}
|
||||
>
|
||||
{col[:label]}
|
||||
</th>
|
||||
<th :for={dyn_col <- @dynamic_cols}>
|
||||
<.live_component
|
||||
module={MvWeb.Components.SortHeaderComponent}
|
||||
|
|
@ -645,6 +655,16 @@ defmodule MvWeb.CoreComponents do
|
|||
"""
|
||||
end
|
||||
|
||||
defp table_th_aria_sort(col, sort_field, sort_order) do
|
||||
col_sort = Map.get(col, :sort_field)
|
||||
|
||||
if not is_nil(col_sort) and col_sort == sort_field and sort_order in [:asc, :desc] do
|
||||
if sort_order == :asc, do: "ascending", else: "descending"
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Renders a data list.
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ defmodule MvWeb.Layouts.Sidebar do
|
|||
"""
|
||||
use MvWeb, :html
|
||||
|
||||
alias MvWeb.PagePaths
|
||||
|
||||
attr :current_user, :map, default: nil, doc: "The current user"
|
||||
attr :club_name, :string, required: true, doc: "The name of the club"
|
||||
attr :mobile, :boolean, default: false, doc: "Whether this is mobile view"
|
||||
|
|
@ -70,34 +72,57 @@ defmodule MvWeb.Layouts.Sidebar do
|
|||
defp sidebar_menu(assigns) do
|
||||
~H"""
|
||||
<ul class="menu flex-1 w-full p-2" role="menubar">
|
||||
<.menu_item
|
||||
href={~p"/members"}
|
||||
icon="hero-users"
|
||||
label={gettext("Members")}
|
||||
/>
|
||||
|
||||
<.menu_item
|
||||
href={~p"/membership_fee_types"}
|
||||
icon="hero-currency-euro"
|
||||
label={gettext("Fee Types")}
|
||||
/>
|
||||
|
||||
<!-- Nested Admin Menu -->
|
||||
<.menu_group icon="hero-cog-6-tooth" label={gettext("Administration")}>
|
||||
<.menu_subitem href={~p"/users"} label={gettext("Users")} />
|
||||
<.menu_subitem href={~p"/groups"} label={gettext("Groups")} />
|
||||
<.menu_subitem href={~p"/admin/roles"} label={gettext("Roles")} />
|
||||
<.menu_subitem
|
||||
href={~p"/membership_fee_settings"}
|
||||
label={gettext("Fee Settings")}
|
||||
<%= if can_access_page?(@current_user, PagePaths.members()) do %>
|
||||
<.menu_item
|
||||
href={~p"/members"}
|
||||
icon="hero-users"
|
||||
label={gettext("Members")}
|
||||
/>
|
||||
<.menu_subitem href={~p"/admin/import-export"} label={gettext("Import/Export")} />
|
||||
<% end %>
|
||||
|
||||
<%= if can_access_page?(@current_user, PagePaths.membership_fee_types()) do %>
|
||||
<.menu_item
|
||||
href={~p"/membership_fee_types"}
|
||||
icon="hero-currency-euro"
|
||||
label={gettext("Fee Types")}
|
||||
/>
|
||||
<% end %>
|
||||
|
||||
<%= if admin_menu_visible?(@current_user) do %>
|
||||
<.menu_group
|
||||
icon="hero-cog-6-tooth"
|
||||
label={gettext("Administration")}
|
||||
testid="sidebar-administration"
|
||||
>
|
||||
<%= if can_access_page?(@current_user, PagePaths.users()) do %>
|
||||
<.menu_subitem href={~p"/users"} label={gettext("Users")} />
|
||||
<% end %>
|
||||
<%= if can_access_page?(@current_user, PagePaths.groups()) do %>
|
||||
<.menu_subitem href={~p"/groups"} label={gettext("Groups")} />
|
||||
<% end %>
|
||||
<%= if can_access_page?(@current_user, PagePaths.admin_roles()) do %>
|
||||
<.menu_subitem href={~p"/admin/roles"} label={gettext("Roles")} />
|
||||
<% end %>
|
||||
<%= if can_access_page?(@current_user, PagePaths.membership_fee_settings()) do %>
|
||||
<.menu_subitem
|
||||
href={~p"/membership_fee_settings"}
|
||||
label={gettext("Fee Settings")}
|
||||
/>
|
||||
<% end %>
|
||||
<%= if can_access_page?(@current_user, PagePaths.settings()) do %>
|
||||
<.menu_subitem href={~p"/admin/import-export"} label={gettext("Import/Export")} />
|
||||
<.menu_subitem href={~p"/settings"} label={gettext("Settings")} />
|
||||
</.menu_group>
|
||||
<% end %>
|
||||
</.menu_group>
|
||||
<% end %>
|
||||
</ul>
|
||||
"""
|
||||
end
|
||||
|
||||
defp admin_menu_visible?(user) do
|
||||
Enum.any?(PagePaths.admin_menu_paths(), &can_access_page?(user, &1))
|
||||
end
|
||||
|
||||
attr :href, :string, required: true, doc: "Navigation path"
|
||||
attr :icon, :string, required: true, doc: "Heroicon name"
|
||||
attr :label, :string, required: true, doc: "Menu item label"
|
||||
|
|
@ -120,12 +145,13 @@ defmodule MvWeb.Layouts.Sidebar do
|
|||
|
||||
attr :icon, :string, required: true, doc: "Heroicon name for the menu group"
|
||||
attr :label, :string, required: true, doc: "Menu group label"
|
||||
attr :testid, :string, default: nil, doc: "data-testid for stable test selectors"
|
||||
slot :inner_block, required: true, doc: "Submenu items"
|
||||
|
||||
defp menu_group(assigns) do
|
||||
~H"""
|
||||
<!-- Expanded Mode: Always open div structure -->
|
||||
<li role="none" class="expanded-menu-group">
|
||||
<li role="none" class="expanded-menu-group" data-testid={@testid}>
|
||||
<div
|
||||
class="flex items-center gap-3"
|
||||
role="group"
|
||||
|
|
@ -139,7 +165,7 @@ defmodule MvWeb.Layouts.Sidebar do
|
|||
</ul>
|
||||
</li>
|
||||
<!-- Collapsed Mode: Dropdown -->
|
||||
<div class="collapsed-menu-group dropdown dropdown-right">
|
||||
<div class="collapsed-menu-group dropdown dropdown-right" data-testid={@testid}>
|
||||
<button
|
||||
type="button"
|
||||
tabindex="0"
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ defmodule MvWeb.TableComponents do
|
|||
type="button"
|
||||
phx-click="sort"
|
||||
phx-value-field={@field}
|
||||
aria-sort={aria_sort(@sort_field, @sort_order, @field)}
|
||||
class="flex items-center gap-1 hover:underline focus:outline-none"
|
||||
>
|
||||
<span>{@label}</span>
|
||||
|
|
@ -33,12 +32,4 @@ defmodule MvWeb.TableComponents do
|
|||
</button>
|
||||
"""
|
||||
end
|
||||
|
||||
defp aria_sort(current_field, current_order, this_field) do
|
||||
cond do
|
||||
current_field != this_field -> "none"
|
||||
current_order == :asc -> "ascending"
|
||||
true -> "descending"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue