defmodule LayoutBuilder do
use Phoenix.LiveComponent
use PetalComponents
import LayoutBuilder.Gettext
alias LayoutBuilder.Layout.Layout
@moduledoc """
`LayoutBuilder` allows you to create a %Layout.Layout{} containing %Layout.Row{} and %Layout.Row{}.
"""
@doc """
LayoutBuilder component
## Examples
<.layout_builder />
"""
slot :content, doc: "Content to show inside each col" do
attr :class, :string, doc: "Custom classes to add"
end
attr :title, :atom, default: :h2, doc: "<hx> title level", values: [:h1, :h2, :h3, :h4, :h5, :h6]
attr :title_class, :string, default: "", doc: "classes to add to <hx>", examples: ["text-2xl font-medium"]
attr :show_title, :boolean, default: true, doc: "show title and paddings", examples: [false]
attr :class, :string, default: "", doc: "classes to pass to layout builder", examples: ["mt-6"]
attr :row_class, :string, default: "flex", doc: "classes to pass to layout builder", examples: ["mt-6"]
attr :edit_layout, :boolean, default: true, doc: "show buttons to add / remove cols and rows from layout builder and show background colors"
attr :layout, Layout, required: true, doc: "layout built", examples: [%Layout{}]
def render(assigns) do
assigns = assigns
|> assign_new(:above, fn -> nil end)
~H"""
<article class={@class}>
<%= if @show_title do %>
<%= Phoenix.HTML.Tag.content_tag(@title, class: "text-sm font-medium text-gray-500 dark:text-gray-400") do %>
<%= gettext("Layout builder") %>
<% end %>
<% end %>
<div class={"mt-1 max-w-3xl w-full flex flex-col bg-white dark:bg-black #{if @show_title, do: "p-6", else: ""}"}>
<%= for row <- @layout.rows do %>
<%= if @above do %>
<div class="flex flex-wrap">
<%= render_slot(@above, row) %>
</div>
<% end %>
<div class={if @edit_layout do "bg-gray-100 dark:bg-gray-900 rounded-lg mb-3 " else "" end <> "#{@row_class} gap-x-3"}>
<%= for col <- row.cols do %>
<%= if @edit_layout do %>
<div class="rounded-lg bg-gray-200 dark:bg-gray-800 flex-1 m-3">
<%= render_slot(@content, col) %>
</div>
<% else %>
<%= render_slot(@content, col) %>
<% end %>
<% end %>
<%= if @edit_layout do %>
<.button color="gray" class="w-20 h-12 m-3" phx-value-row={row.id} phx-click="add_column" phx-target={@myself}>
<Heroicons.plus class="w-6 h-6" />
</.button>
<% end %>
</div>
<% end %>
<%= if @edit_layout do %>
<.button color="gray" class="w-full h-12 m-3" phx-click="add_row" phx-target={@myself}>
<Heroicons.plus class="w-6 h-6" />
</.button>
<% end %>
</div>
</article>
"""
end
@spec handle_event(String.t(), map, Elixir.Phoenix.LiveView.Socket.t()) :: {:noreply, Elixir.Phoenix.LiveView.Socket.t()}
def handle_event("add_column", %{"row" => id}, socket) do
row = Enum.find(socket.assigns.layout.rows, fn row -> row.id == id end)
layout = Layout.add_col(socket.assigns.layout, row)
send(self(), %{layout: layout})
{:noreply, socket}
end
def handle_event("add_row", _, socket) do
layout = Layout.add_row(socket.assigns.layout)
send(self(), %{layout: layout})
{:noreply, assign(socket, :layout, layout)}
end
end