defmodule MvWeb.Components.ViewSettingsDropdownComponent do @moduledoc """ LiveComponent for the member-overview view settings (§1.20). Renders an icon button with a tooltip that opens a dropdown of toggles: * Compact mode — table row density (compact ↔ comfortable) * Compact Member field — composite last+first name cell, with a sub-toggle "include email" * Compact address field — composite street / postal+city cell Turning a composite field off surfaces the underlying separate columns in the table. The component is display-only: it emits `{:view_setting_toggled, key}` to the parent LiveView, which owns and persists the settings. ## Props - `:density` — `:compact` or `:comfortable` - `:compact_member` — boolean - `:member_include_email` — boolean - `:compact_address` — boolean - `:id` — component id """ use MvWeb, :live_component @impl true def update(assigns, socket) do {:ok, socket |> assign(assigns) |> assign_new(:open, fn -> false end)} end @impl true def render(assigns) do ~H"""
<.dropdown_menu id="view-settings-menu" icon="hero-cog-6-tooth" button_label={gettext("View")} open={@open} phx_target={@myself} menu_width="w-72" testid="view-settings" button_testid="view-settings-button" >
  • {gettext("View settings")}
  • <.toggle_item setting="density" label={gettext("Compact mode")} checked={@density == :compact} target={@myself} /> <.toggle_item setting="compact_member" label={gettext("Compact Member field")} checked={@compact_member} target={@myself} /> <%!-- The email line lives inside the composite Member cell, so this sub-toggle is only meaningful while that cell is compact. When the composite is off, email is its own column and this toggle is omitted. --%>
  • <.toggle_item setting="member_include_email" label={gettext("include email")} checked={@member_include_email} target={@myself} />
  • <.toggle_item setting="compact_address" label={gettext("Compact address field")} checked={@compact_address} target={@myself} />
    """ end attr :setting, :string, required: true attr :label, :string, required: true attr :checked, :boolean, required: true attr :target, :any, required: true defp toggle_item(assigns) do ~H""" """ end @impl true def handle_event("toggle_dropdown", _params, socket) do {:noreply, assign(socket, :open, !socket.assigns.open)} end def handle_event("close_dropdown", _params, socket) do {:noreply, assign(socket, :open, false)} end def handle_event("toggle", %{"setting" => setting}, socket) do send(self(), {:view_setting_toggled, String.to_existing_atom(setting)}) {:noreply, socket} end end