feat: reuse form_section in settings
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
carla 2025-12-04 12:32:24 +01:00
parent 89b02aeacf
commit 8512be0282
4 changed files with 209 additions and 169 deletions

View file

@ -153,7 +153,7 @@ defmodule MvWeb.CoreComponents do
aria-haspopup="menu" aria-haspopup="menu"
aria-expanded={@open} aria-expanded={@open}
aria-controls={@id} aria-controls={@id}
class="btn btn-ghost" class="btn"
phx-click="toggle_dropdown" phx-click="toggle_dropdown"
phx-target={@phx_target} phx-target={@phx_target}
data-testid="dropdown-button" data-testid="dropdown-button"
@ -236,6 +236,30 @@ defmodule MvWeb.CoreComponents do
""" """
end end
@doc """
Renders a section in with a border similar to cards.
## Examples
<.form_section title={gettext("Personal Data")}>
<p>input</p>
</form_section>
"""
attr :title, :string, required: true
slot :inner_block, required: true
def form_section(assigns) do
~H"""
<section class="mb-6">
<h2 class="text-lg font-semibold mb-3">{@title}</h2>
<div class="border border-base-300 rounded-lg p-4 bg-base-100">
{render_slot(@inner_block)}
</div>
</section>
"""
end
@doc """ @doc """
Renders an input with label and error messages. Renders an input with label and error messages.
@ -434,7 +458,7 @@ defmodule MvWeb.CoreComponents do
~H""" ~H"""
<header class={[@actions != [] && "flex items-center justify-between gap-6", "pb-4", @class]}> <header class={[@actions != [] && "flex items-center justify-between gap-6", "pb-4", @class]}>
<div> <div>
<h1 class="text-lg font-semibold leading-8"> <h1 class="text-xl font-semibold leading-8">
{render_slot(@inner_block)} {render_slot(@inner_block)}
</h1> </h1>
<p :if={@subtitle != []} class="text-sm text-base-content/70"> <p :if={@subtitle != []} class="text-sm text-base-content/70">
@ -474,6 +498,7 @@ defmodule MvWeb.CoreComponents do
slot :col, required: true do slot :col, required: true do
attr :label, :string attr :label, :string
attr :class, :string
end end
slot :action, doc: "the slot for showing user actions in the last table column" slot :action, doc: "the slot for showing user actions in the last table column"
@ -489,7 +514,7 @@ defmodule MvWeb.CoreComponents do
<table class="table table-zebra"> <table class="table table-zebra">
<thead> <thead>
<tr> <tr>
<th :for={col <- @col}>{col[:label]}</th> <th :for={col <- @col} class={Map.get(col, :class)}>{col[:label]}</th>
<th :for={dyn_col <- @dynamic_cols}> <th :for={dyn_col <- @dynamic_cols}>
<.live_component <.live_component
module={MvWeb.Components.SortHeaderComponent} module={MvWeb.Components.SortHeaderComponent}
@ -510,7 +535,33 @@ defmodule MvWeb.CoreComponents do
<td <td
:for={col <- @col} :for={col <- @col}
phx-click={@row_click && @row_click.(row)} phx-click={@row_click && @row_click.(row)}
class={["max-w-xs truncate", @row_click && "hover:cursor-pointer"]} class={
col_class = Map.get(col, :class)
classes = ["max-w-xs"]
classes =
if col_class == nil || (col_class && !String.contains?(col_class, "text-center")) do
["truncate" | classes]
else
classes
end
classes =
if @row_click do
["hover:cursor-pointer" | classes]
else
classes
end
classes =
if col_class do
[col_class | classes]
else
classes
end
Enum.join(classes, " ")
}
> >
{render_slot(col, @row_item.(row))} {render_slot(col, @row_item.(row))}
</td> </td>

View file

@ -20,9 +20,16 @@ defmodule MvWeb.CustomFieldLive.IndexComponent do
<div id={@id}> <div id={@id}>
<.form_section title={gettext("Custom Fields")}> <.form_section title={gettext("Custom Fields")}>
<div class="flex"> <div class="flex">
<p class="text-sm text-base-content/70">{gettext("These will appear in addition to other data when adding new members.")}</p> <p class="text-sm text-base-content/70">
{gettext("These will appear in addition to other data when adding new members.")}
</p>
<div class="ml-auto"> <div class="ml-auto">
<.button class="ml-auto" variant="primary" phx-click="new_custom_field" phx-target={@myself}> <.button
class="ml-auto"
variant="primary"
phx-click="new_custom_field"
phx-target={@myself}
>
<.icon name="hero-plus" /> {gettext("New Custom field")} <.icon name="hero-plus" /> {gettext("New Custom field")}
</.button> </.button>
</div> </div>
@ -61,7 +68,11 @@ defmodule MvWeb.CustomFieldLive.IndexComponent do
{custom_field.description} {custom_field.description}
</:col> </:col>
<:col :let={{_id, custom_field}} label={gettext("Show in overview")} class="max-w-[9.375rem] text-center"> <:col
:let={{_id, custom_field}}
label={gettext("Show in overview")}
class="max-w-[9.375rem] text-center"
>
<span :if={custom_field.show_in_overview} class="badge badge-success"> <span :if={custom_field.show_in_overview} class="badge badge-success">
{gettext("Yes")} {gettext("Yes")}
</span> </span>
@ -71,22 +82,19 @@ defmodule MvWeb.CustomFieldLive.IndexComponent do
</:col> </:col>
<:action :let={{_id, custom_field}}> <:action :let={{_id, custom_field}}>
<.icon_button <.link phx-click={
icon="hero-pencil" JS.push("edit_custom_field", value: %{id: custom_field.id}, target: @myself)
label={gettext("Edit custom field")} }>
size="sm" {gettext("Edit")}
phx-click={JS.push("edit_custom_field", value: %{id: custom_field.id}, target: @myself)} </.link>
/>
</:action> </:action>
<:action :let={{_id, custom_field}}> <:action :let={{_id, custom_field}}>
<.icon_button <.link phx-click={
icon="hero-trash" JS.push("prepare_delete", value: %{id: custom_field.id}, target: @myself)
label={gettext("Delete custom field")} }>
size="sm" {gettext("Delete")}
class="btn-error" </.link>
phx-click={JS.push("prepare_delete", value: %{id: custom_field.id}, target: @myself)}
/>
</:action> </:action>
</.table> </.table>

View file

@ -46,22 +46,22 @@ defmodule MvWeb.GlobalSettingsLive do
</.header> </.header>
<%!-- Club Settings Section --%> <%!-- Club Settings Section --%>
<.header> <.form_section title={gettext("Club Settings")}>
{gettext("Club Settings")}
</.header>
<.form for={@form} id="settings-form" phx-change="validate" phx-submit="save"> <.form for={@form} id="settings-form" phx-change="validate" phx-submit="save">
<div class="w-100">
<.input <.input
field={@form[:club_name]} field={@form[:club_name]}
type="text" type="text"
label={gettext("Association Name")} label={gettext("Association Name")}
required required
/> />
</div>
<.button phx-disable-with={gettext("Saving...")} variant="primary"> <.button phx-disable-with={gettext("Saving...")} variant="primary">
{gettext("Save Settings")} {gettext("Save Settings")}
</.button> </.button>
</.form> </.form>
</.form_section>
<%!-- Custom Fields Section --%> <%!-- Custom Fields Section --%>
<.live_component <.live_component
module={MvWeb.CustomFieldLive.IndexComponent} module={MvWeb.CustomFieldLive.IndexComponent}

View file

@ -348,25 +348,6 @@ defmodule MvWeb.MemberLive.Form do
defp return_path("show", nil), do: ~p"/members" defp return_path("show", nil), do: ~p"/members"
defp return_path("show", member), do: ~p"/members/#{member.id}" defp return_path("show", member), do: ~p"/members/#{member.id}"
# -----------------------------------------------------------------
# Helper Components
# -----------------------------------------------------------------
# Renders a form section box with border and title.
attr :title, :string, required: true
slot :inner_block, required: true
defp form_section(assigns) do
~H"""
<section class="mb-6">
<h2 class="text-lg font-semibold mb-3">{@title}</h2>
<div class="border border-base-300 rounded-lg p-4 bg-base-100">
{render_slot(@inner_block)}
</div>
</section>
"""
end
# ----------------------------------------------------------------- # -----------------------------------------------------------------
# Helper Functions for Custom Fields # Helper Functions for Custom Fields
# ----------------------------------------------------------------- # -----------------------------------------------------------------