diff --git a/assets/css/app.css b/assets/css/app.css
index b754a08..97961ab 100644
--- a/assets/css/app.css
+++ b/assets/css/app.css
@@ -181,29 +181,6 @@
padding-left: 14px;
}
-/* ============================================
- Menu Groups - Disable hover and active on expanded-menu-group header
- ============================================ */
-
-/* Disable all interactive effects on expanded-menu-group header (no href, not clickable)
- Using [role="group"] to increase specificity and avoid !important */
-.sidebar .menu > li.expanded-menu-group > div[role="group"]:not(a) {
- pointer-events: none;
- cursor: default;
-}
-
-/* Higher specificity selector to override DaisyUI menu hover styles
- DaisyUI uses :where() which has 0 specificity, but the compiled CSS might have higher specificity
- Using [role="group"] attribute selector increases specificity without !important */
-.sidebar .menu > li.expanded-menu-group > div[role="group"]:not(a):hover,
-.sidebar .menu > li.expanded-menu-group > div[role="group"]:not(a):active,
-.sidebar .menu > li.expanded-menu-group > div[role="group"]:not(a):focus {
- background-color: transparent;
- box-shadow: none;
- cursor: default;
- color: inherit;
-}
-
/* ============================================
Elements Only Visible in Expanded State
============================================ */
@@ -240,9 +217,7 @@
- Menu has p-2 (8px), so links need 14px additional padding-left */
.sidebar .menu > li > a,
-.sidebar .menu > li > button,
-.sidebar .menu > li.expanded-menu-group > div,
-.sidebar .menu > div.collapsed-menu-group > button {
+.sidebar .menu > li > button {
@apply transition-all duration-300;
padding-left: 14px;
}
@@ -251,17 +226,12 @@
- Remove gap so label (which is opacity-0 w-0) doesn't create space
- Keep padding-left at 14px so icons stay centered under logo */
[data-sidebar-expanded="false"] .sidebar .menu > li > a,
-[data-sidebar-expanded="false"] .sidebar .menu > li > button,
-[data-sidebar-expanded="false"] .sidebar .menu > li.expanded-menu-group > div,
-[data-sidebar-expanded="false"] .sidebar .menu > div.collapsed-menu-group > button {
+[data-sidebar-expanded="false"] .sidebar .menu > li > button {
@apply gap-0;
padding-left: 14px;
padding-right: 14px; /* Center icon horizontally in 64px sidebar */
}
-
-
-
/* ============================================
Footer Button Alignment - Left Aligned in Collapsed State
============================================ */
diff --git a/config/test.exs b/config/test.exs
index 45acaa4..326694e 100644
--- a/config/test.exs
+++ b/config/test.exs
@@ -12,7 +12,7 @@ config :mv, Mv.Repo,
port: System.get_env("TEST_POSTGRES_PORT", "5000"),
database: "mv_test#{System.get_env("MIX_TEST_PARTITION")}",
pool: Ecto.Adapters.SQL.Sandbox,
- pool_size: System.schedulers_online() * 4
+ pool_size: System.schedulers_online() * 2
# We don't run a server during test. If one is required,
# you can enable the server option below.
diff --git a/lib/mv_web/components/layouts/sidebar.ex b/lib/mv_web/components/layouts/sidebar.ex
index 33319d4..6f7e684 100644
--- a/lib/mv_web/components/layouts/sidebar.ex
+++ b/lib/mv_web/components/layouts/sidebar.ex
@@ -75,23 +75,30 @@ defmodule MvWeb.Layouts.Sidebar do
icon="hero-users"
label={gettext("Members")}
/>
+ <.menu_item
+ href={~p"/users"}
+ icon="hero-user-circle"
+ label={gettext("Users")}
+ />
+ <.menu_item
+ href={~p"/custom_field_values"}
+ icon="hero-rectangle-group"
+ label={gettext("Custom Fields")}
+ />
+
+ <.menu_group
+ icon="hero-currency-dollar"
+ label={gettext("Contributions")}
+ >
+ <.menu_subitem href="/contribution_types" label={gettext("Contribution Types")} />
+ <.menu_subitem href="/membership_fee_settings" label={gettext("Settings")} />
+
<.menu_item
- href={~p"/membership_fee_types"}
- icon="hero-currency-euro"
- label={gettext("Fee Types")}
+ href={~p"/settings"}
+ icon="hero-cog-6-tooth"
+ label={gettext("Settings")}
/>
-
-
- <.menu_group icon="hero-cog-6-tooth" label={gettext("Administration")}>
- <.menu_subitem href={~p"/users"} label={gettext("Users")} />
- <.menu_subitem href={~p"/admin/roles"} label={gettext("Roles")} />
- <.menu_subitem
- href={~p"/membership_fee_settings"}
- label={gettext("Fee Settings")}
- />
- <.menu_subitem href={~p"/settings"} label={gettext("Settings")} />
-
"""
end
@@ -122,41 +129,43 @@ defmodule MvWeb.Layouts.Sidebar do
defp menu_group(assigns) do
~H"""
-
-
-
- <.icon name={@icon} class="size-5 shrink-0" aria-hidden="true" />
-
+
-
-
"""
end
diff --git a/priv/gettext/de/LC_MESSAGES/default.po b/priv/gettext/de/LC_MESSAGES/default.po
index 6264697..33dff0f 100644
--- a/priv/gettext/de/LC_MESSAGES/default.po
+++ b/priv/gettext/de/LC_MESSAGES/default.po
@@ -631,6 +631,7 @@ msgstr "Benutzerdefinierter Feldwert erfolgreich %{action}"
msgid "Please select a custom field first"
msgstr "Bitte wähle zuerst ein Benutzerdefiniertes Feld"
+#: lib/mv_web/components/layouts/sidebar.ex
#: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format
@@ -914,6 +915,7 @@ msgstr "Beitragsart ändern"
msgid "Contribution Start"
msgstr "Beitragsbeginn"
+#: lib/mv_web/components/layouts/sidebar.ex
#: lib/mv_web/live/contribution_type_live/index.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Contribution Types"
@@ -924,6 +926,11 @@ msgstr "Beitragsarten"
msgid "Contribution type"
msgstr "Beitragsart"
+#: lib/mv_web/components/layouts/sidebar.ex
+#, elixir-autogen, elixir-format, fuzzy
+msgid "Contributions"
+msgstr "Beiträge"
+
#: lib/mv_web/live/contribution_period_live/show.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Contributions for %{name}"
@@ -2181,28 +2188,3 @@ msgstr "Mitglied wurde erfolgreich erstellt"
#, elixir-autogen, elixir-format
msgid "Member updated successfully"
msgstr "Mitglied wurde erfolgreich aktualisiert"
-
-#: lib/mv_web/components/layouts/sidebar.ex
-#, elixir-autogen, elixir-format, fuzzy
-msgid "Roles"
-msgstr "Rollen"
-
-#: lib/mv_web/components/layouts/sidebar.ex
-#, elixir-autogen, elixir-format, fuzzy
-msgid "Fee Settings"
-msgstr "Beitragseinstellungen"
-
-#: lib/mv_web/components/layouts/sidebar.ex
-#, elixir-autogen, elixir-format
-msgid "Fee Types"
-msgstr "Beitragstypen"
-
-#: lib/mv_web/components/layouts/sidebar.ex
-#, elixir-autogen, elixir-format
-msgid "Administration"
-msgstr "Administration"
-
-#~ #: lib/mv_web/components/layouts/sidebar.ex
-#~ #, elixir-autogen, elixir-format, fuzzy
-#~ msgid "Contributions"
-#~ msgstr "Beiträge"
diff --git a/priv/gettext/default.pot b/priv/gettext/default.pot
index b7e0ceb..4124d86 100644
--- a/priv/gettext/default.pot
+++ b/priv/gettext/default.pot
@@ -632,6 +632,7 @@ msgstr ""
msgid "Please select a custom field first"
msgstr ""
+#: lib/mv_web/components/layouts/sidebar.ex
#: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format
@@ -915,6 +916,7 @@ msgstr ""
msgid "Contribution Start"
msgstr ""
+#: lib/mv_web/components/layouts/sidebar.ex
#: lib/mv_web/live/contribution_type_live/index.ex
#, elixir-autogen, elixir-format
msgid "Contribution Types"
@@ -925,6 +927,11 @@ msgstr ""
msgid "Contribution type"
msgstr ""
+#: lib/mv_web/components/layouts/sidebar.ex
+#, elixir-autogen, elixir-format
+msgid "Contributions"
+msgstr ""
+
#: lib/mv_web/live/contribution_period_live/show.ex
#, elixir-autogen, elixir-format
msgid "Contributions for %{name}"
@@ -2182,23 +2189,3 @@ msgstr ""
#, elixir-autogen, elixir-format
msgid "Member updated successfully"
msgstr ""
-
-#: lib/mv_web/components/layouts/sidebar.ex
-#, elixir-autogen, elixir-format
-msgid "Roles"
-msgstr ""
-
-#: lib/mv_web/components/layouts/sidebar.ex
-#, elixir-autogen, elixir-format
-msgid "Fee Settings"
-msgstr ""
-
-#: lib/mv_web/components/layouts/sidebar.ex
-#, elixir-autogen, elixir-format
-msgid "Fee Types"
-msgstr ""
-
-#: lib/mv_web/components/layouts/sidebar.ex
-#, elixir-autogen, elixir-format
-msgid "Administration"
-msgstr ""
diff --git a/priv/gettext/en/LC_MESSAGES/default.po b/priv/gettext/en/LC_MESSAGES/default.po
index 6001b60..50c5440 100644
--- a/priv/gettext/en/LC_MESSAGES/default.po
+++ b/priv/gettext/en/LC_MESSAGES/default.po
@@ -632,6 +632,7 @@ msgstr ""
msgid "Please select a custom field first"
msgstr ""
+#: lib/mv_web/components/layouts/sidebar.ex
#: lib/mv_web/live/member_live/form.ex
#: lib/mv_web/live/member_live/show.ex
#, elixir-autogen, elixir-format, fuzzy
@@ -915,6 +916,7 @@ msgstr ""
msgid "Contribution Start"
msgstr ""
+#: lib/mv_web/components/layouts/sidebar.ex
#: lib/mv_web/live/contribution_type_live/index.ex
#, elixir-autogen, elixir-format
msgid "Contribution Types"
@@ -925,6 +927,11 @@ msgstr ""
msgid "Contribution type"
msgstr ""
+#: lib/mv_web/components/layouts/sidebar.ex
+#, elixir-autogen, elixir-format
+msgid "Contributions"
+msgstr ""
+
#: lib/mv_web/live/contribution_period_live/show.ex
#, elixir-autogen, elixir-format
msgid "Contributions for %{name}"
@@ -2182,33 +2189,3 @@ msgstr "Member created successfully"
#, elixir-autogen, elixir-format
msgid "Member updated successfully"
msgstr "Member updated successfully"
-
-#: lib/mv_web/components/layouts/sidebar.ex
-#, elixir-autogen, elixir-format, fuzzy
-msgid "Roles"
-msgstr ""
-
-#: lib/mv_web/components/layouts/sidebar.ex
-#, elixir-autogen, elixir-format, fuzzy
-msgid "Fee Settings"
-msgstr ""
-
-#: lib/mv_web/components/layouts/sidebar.ex
-#, elixir-autogen, elixir-format
-msgid "Fee Types"
-msgstr ""
-
-#: lib/mv_web/components/layouts/sidebar.ex
-#, elixir-autogen, elixir-format
-msgid "Administration"
-msgstr ""
-
-#~ #: lib/mv_web/components/layouts/sidebar.ex
-#~ #, elixir-autogen, elixir-format, fuzzy
-#~ msgid "Admin"
-#~ msgstr ""
-
-#~ #: lib/mv_web/components/layouts/sidebar.ex
-#~ #, elixir-autogen, elixir-format
-#~ msgid "Contributions"
-#~ msgstr ""
diff --git a/test/mv_web/components/layouts/sidebar_test.exs b/test/mv_web/components/layouts/sidebar_test.exs
index 75727e3..41bbbd7 100644
--- a/test/mv_web/components/layouts/sidebar_test.exs
+++ b/test/mv_web/components/layouts/sidebar_test.exs
@@ -122,34 +122,35 @@ defmodule MvWeb.Layouts.SidebarTest do
test "T2.2: does not render menu items when current_user is nil" do
html = render_sidebar(guest_assigns())
- # Navigation menu should not be rendered
- refute html =~ ~s(role="menubar")
- refute html =~ ~s(role="menuitem")
+ # Navigation links should not be rendered
+ refute html =~ ~s(href="/members")
+ refute html =~ ~s(href="/users")
+ refute html =~ ~s(href="/settings")
+ refute html =~ ~s(href="/contribution_types")
# Footer section should not be rendered
- refute html =~ "theme-controller"
refute html =~ "locale-select"
+ refute html =~ "theme-controller"
end
test "T2.3: renders menu items when current_user is present" do
html = render_sidebar(authenticated_assigns())
- # Check that menu structure exists
- assert html =~ ~s(role="menubar")
- assert html =~ ~s(role="menuitem")
+ # Check for Members link
+ assert html =~ ~s(href="/members")
- # Check that top-level menu items exist (at least one)
- # Count menu items with tooltips (top-level items have tooltips)
- menu_item_count = html |> String.split("data-tip=") |> length() |> Kernel.-(1)
- assert menu_item_count > 0, "Should have at least one top-level menu item"
+ # Check for Users link
+ assert html =~ ~s(href="/users")
- # Check that nested menu groups exist
- assert html =~ ~s(
)
- assert html =~ ~s(role="group")
- assert has_class?(html, "expanded-menu-group")
+ # Check for Custom Fields link
+ assert html =~ ~s(href="/custom_field_values")
- # Check that nested menu items exist
- assert html =~ ~s(role="menu")
+ # Check for Contributions section
+ assert html =~ ~s(href="/contribution_types")
+ assert html =~ ~s(href="/membership_fee_settings")
+
+ # Check for Settings link (placeholder)
+ assert html =~ ~s(href="/settings")
end
test "T2.4: renders sidebar with main-sidebar ID" do
@@ -173,59 +174,51 @@ defmodule MvWeb.Layouts.SidebarTest do
test "T3.1: renders flat menu items with icons and labels" do
html = render_sidebar(authenticated_assigns())
- # Check that top-level menu items have structure
- # Top-level items have tooltips
+ # Check for Members link with icon
+ assert html =~ ~s(href="/members")
+ assert html =~ "hero-users"
+
+ # Check for Users link with icon
+ assert html =~ ~s(href="/users")
+ assert html =~ "hero-user-circle"
+
+ # Check for Custom Fields link with icon
+ assert html =~ ~s(href="/custom_field_values")
+ assert html =~ "hero-rectangle-group"
+
+ # Check for Settings link with icon
+ assert html =~ ~s(href="/settings")
+ assert html =~ "hero-cog-6-tooth"
+
+ # Check for tooltips (data-tip attribute)
assert html =~ "data-tip="
- assert has_class?(html, "tooltip")
- assert has_class?(html, "tooltip-right")
-
- # Check that menu items have icons (hero-* classes)
- assert html =~ ~r/hero-\w+/
-
- # Check that menu items have labels
- assert has_class?(html, "menu-label")
-
- # Check that menu items have links
- assert html =~ ~s(role="menuitem")
end
test "T3.2: renders nested menu with details element for expanded state" do
html = render_sidebar(authenticated_assigns())
- # Check for nested menu structure
- assert html =~ ~s()
- assert html =~ ~s(role="group")
- assert html =~ ~s(aria-label="Administration")
+ # Check for Contributions section structure with details
+ assert html =~ " String.split(~s(role="menuitem")) |> length() |> Kernel.-(1)
- data_tip_count = html |> String.split("data-tip=") |> length() |> Kernel.-(1)
-
- # There should be more menuitems than data-tips (nested items don't have data-tip)
- assert menuitem_count > data_tip_count,
- "Should have nested menu items (menuitems without data-tip)"
+ # Check for contribution links
+ assert html =~ ~s(href="/contribution_types")
+ assert html =~ ~s(href="/membership_fee_settings")
end
test "T3.3: renders nested menu with dropdown for collapsed state" do
html = render_sidebar(authenticated_assigns())
- # Check for collapsed dropdown structure
+ # Check for collapsed dropdown container
assert has_class?(html, "collapsed-menu-group")
assert has_class?(html, "dropdown")
assert has_class?(html, "dropdown-right")
+
+ # Check for dropdown-content
assert has_class?(html, "dropdown-content")
- # Check that dropdown button has icon (any hero icon)
- assert html =~ ~r/hero-\w+/
-
- # Check ARIA attributes
+ # Check for icon button
+ assert html =~ "hero-currency-dollar"
assert html =~ ~s(aria-haspopup="menu")
end
end
@@ -353,9 +346,8 @@ defmodule MvWeb.Layouts.SidebarTest do
test "T5.4: nested menu has correct ARIA attributes" do
html = render_sidebar(authenticated_assigns())
- # Expanded mode should have role="group" with aria-label
- assert html =~ ~s(role="group")
- assert html =~ ~s(aria-label="Administration")
+ # Details summary should have haspopup
+ assert html =~ ~s(aria-haspopup="true")
# Dropdown button should have haspopup
assert html =~ ~s(aria-haspopup="menu")
@@ -422,17 +414,17 @@ defmodule MvWeb.Layouts.SidebarTest do
test "T7.1: renders hero icons for menu items" do
html = render_sidebar(authenticated_assigns())
- # Check that hero icons are present (pattern matching)
- assert html =~ ~r/hero-\w+/
-
- # Check that icons have aria-hidden
- assert html =~ ~s(aria-hidden="true")
-
- # Check for specific structural icons (toggle, theme) that should always exist
+ # Check for hero icons
+ assert html =~ "hero-users"
+ assert html =~ "hero-user-circle"
+ assert html =~ "hero-rectangle-group"
+ assert html =~ "hero-currency-dollar"
+ assert html =~ "hero-cog-6-tooth"
assert html =~ "hero-chevron-left"
assert html =~ "hero-chevron-right"
- assert html =~ "hero-sun"
- assert html =~ "hero-moon"
+
+ # Icons should have aria-hidden
+ assert html =~ ~s(aria-hidden="true")
end
test "T7.2: renders icons for theme toggle" do
@@ -511,25 +503,26 @@ defmodule MvWeb.Layouts.SidebarTest do
# Header section
assert html =~ "Mila Logo"
- assert html =~ ~s(src="/images/mila.svg")
# Navigation section
assert html =~ ~s(role="menubar")
- assert html =~ ~s(id="main-sidebar")
-
- # Check that menu has items (at least one top-level item)
- assert html =~ ~s(role="menuitem")
-
- # Check that nested menus exist
- assert html =~ ~s()
- assert html =~ ~s(role="group")
# Footer section
assert html =~ "theme-controller"
- assert html =~ ~s(action="/set_locale")
- # Check that critical navigation exists (at least /members)
- assert html =~ ~s(href="/members"), "Critical /members route should exist"
+ # All expected links
+ expected_links = [
+ "/members",
+ "/users",
+ "/custom_field_values",
+ "/contribution_types",
+ "/membership_fee_settings",
+ "/sign-out"
+ ]
+
+ for link <- expected_links do
+ assert html =~ ~s(href="#{link}"), "Missing link: #{link}"
+ end
end
end
@@ -628,10 +621,9 @@ defmodule MvWeb.Layouts.SidebarTest do
test "renders expanded menu group" do
html = render_sidebar(authenticated_assigns())
- # expanded-menu-group structure present
- assert html =~ ~s()
- assert html =~ ~s(role="group")
- assert html =~ ~s(aria-label="Administration")
+ # details/summary present
+ assert html =~ " String.split(~s(role="menuitem")) |> length() |> Kernel.-(1)
- data_tip_count = html |> String.split("data-tip=") |> length() |> Kernel.-(1)
-
- # There should be more menuitems than data-tips (nested items don't have data-tip)
- assert menuitem_count > data_tip_count,
- "Should have nested menu items (menuitems without data-tip)"
-
- # Verify nested menu structure exists
+ # Inner_block items rendered
+ assert html =~ ~s(href="/contribution_types")
+ assert html =~ ~s(href="/membership_fee_settings")
assert html =~ ~s(role="menu")
end
end
@@ -841,10 +821,9 @@ defmodule MvWeb.Layouts.SidebarTest do
assert has_class?(html, "expanded-menu-group")
assert has_class?(html, "collapsed-menu-group")
- # Expanded menu group should have correct structure
- # (CSS handles hover effects, but we verify structure)
- assert html =~ ~s()
- assert html =~ ~s(role="group")
+ # Details element should not have duplicate hover classes
+ # (CSS handles this, but we verify structure)
+ assert html =~ "