fix(elixir): show deeply nested categories

This commit is contained in:
Schuwi
2025-09-14 15:38:02 +02:00
parent ad12ae2ec7
commit 5717931ace

View File

@@ -159,6 +159,77 @@ defmodule ComponentsElixirWeb.CategoriesLive do
Inventory.count_components_in_category(category_id)
end
# Component for rendering individual category items
defp category_item(assigns) do
# Calculate margin based on depth (0 = no margin, 1+ = incremental margin)
margin_left = if assigns.depth == 0, do: 0, else: 32 + assigns.depth * 16
# Determine border style based on depth
border_class = if assigns.depth > 0, do: "border-l-2 border-gray-200 pl-6", else: ""
# Icon size and button size based on depth
{icon_size, button_size, text_size, title_tag} = case assigns.depth do
0 -> {"w-5 h-5", "p-2", "text-lg", "h3"}
1 -> {"w-4 h-4", "p-1.5", "text-base", "h4"}
_ -> {"w-3 h-3", "p-1", "text-sm", "h5"}
end
assigns = assigns
|> assign(:margin_left, margin_left)
|> assign(:border_class, border_class)
|> assign(:icon_size, icon_size)
|> assign(:button_size, button_size)
|> assign(:text_size, text_size)
|> assign(:title_tag, title_tag)
|> assign(:children, child_categories(assigns.categories, assigns.category.id))
~H"""
<div class={[@border_class, @depth > 0 && "mt-4"]} style={"margin-left: #{@margin_left}px"}>
<div class="flex items-center justify-between">
<div class="flex-1">
<div class="flex items-center">
<.icon name="hero-folder" class={"#{@icon_size} #{if @depth == 0, do: "text-indigo-500", else: "text-gray-400"} mr-3"} />
<div>
<%= if @title_tag == "h3" do %>
<h3 class={"#{@text_size} font-medium #{if @depth == 0, do: "text-gray-900", else: "text-gray-700"}"}>{@category.name}</h3>
<% else %>
<h4 class={"#{@text_size} font-medium #{if @depth == 0, do: "text-gray-900", else: "text-gray-700"}"}>{@category.name}</h4>
<% end %>
<%= if @category.description do %>
<p class="text-sm text-gray-500 mt-1">{@category.description}</p>
<% end %>
<p class="text-xs text-gray-400 mt-1">
{count_components_in_category(@category.id)} components
</p>
</div>
</div>
</div>
<div class="flex items-center space-x-2">
<button
phx-click="show_edit_form"
phx-value-id={@category.id}
class={"inline-flex items-center #{@button_size} border border-transparent rounded-full shadow-sm text-white bg-blue-600 hover:bg-blue-700"}
>
<.icon name="hero-pencil" class={@icon_size} />
</button>
<button
phx-click="delete_category"
phx-value-id={@category.id}
data-confirm="Are you sure you want to delete this category? This action cannot be undone."
class={"inline-flex items-center #{@button_size} border border-transparent rounded-full shadow-sm text-white bg-red-600 hover:bg-red-700"}
>
<.icon name="hero-trash" class={@icon_size} />
</button>
</div>
</div>
<!-- Render children recursively -->
<%= for child <- @children do %>
<.category_item category={child} categories={@categories} depth={@depth + 1} />
<% end %>
</div>
"""
end
@impl true
def render(assigns) do
~H"""
@@ -334,83 +405,14 @@ defmodule ComponentsElixirWeb.CategoriesLive do
</div>
</div>
<% else %>
<ul class="divide-y divide-gray-200">
<!-- Root Categories -->
<div class="divide-y divide-gray-200">
<!-- Recursive Category Tree -->
<%= for category <- root_categories(@categories) do %>
<li class="px-6 py-4">
<div class="flex items-center justify-between">
<div class="flex-1">
<div class="flex items-center">
<.icon name="hero-folder" class="w-5 h-5 text-indigo-500 mr-3" />
<div>
<h3 class="text-lg font-medium text-gray-900">{category.name}</h3>
<%= if category.description do %>
<p class="text-sm text-gray-500 mt-1">{category.description}</p>
<% end %>
<p class="text-xs text-gray-400 mt-1">
{count_components_in_category(category.id)} components
</p>
</div>
</div>
</div>
<div class="flex items-center space-x-2">
<button
phx-click="show_edit_form"
phx-value-id={category.id}
class="inline-flex items-center p-2 border border-transparent rounded-full shadow-sm text-white bg-blue-600 hover:bg-blue-700"
>
<.icon name="hero-pencil" class="w-4 h-4" />
</button>
<button
phx-click="delete_category"
phx-value-id={category.id}
data-confirm="Are you sure you want to delete this category? This action cannot be undone."
class="inline-flex items-center p-2 border border-transparent rounded-full shadow-sm text-white bg-red-600 hover:bg-red-700"
>
<.icon name="hero-trash" class="w-4 h-4" />
</button>
</div>
</div>
<!-- Child Categories -->
<%= for child <- child_categories(@categories, category.id) do %>
<div class="ml-8 mt-4 flex items-center justify-between border-l-2 border-gray-200 pl-6">
<div class="flex-1">
<div class="flex items-center">
<.icon name="hero-folder" class="w-4 h-4 text-gray-400 mr-3" />
<div>
<h4 class="text-base font-medium text-gray-700">{child.name}</h4>
<%= if child.description do %>
<p class="text-sm text-gray-500 mt-1">{child.description}</p>
<% end %>
<p class="text-xs text-gray-400 mt-1">
{count_components_in_category(child.id)} components
</p>
</div>
</div>
</div>
<div class="flex items-center space-x-2">
<button
phx-click="show_edit_form"
phx-value-id={child.id}
class="inline-flex items-center p-1.5 border border-transparent rounded-full shadow-sm text-white bg-blue-600 hover:bg-blue-700"
>
<.icon name="hero-pencil" class="w-3 h-3" />
</button>
<button
phx-click="delete_category"
phx-value-id={child.id}
data-confirm="Are you sure you want to delete this category? This action cannot be undone."
class="inline-flex items-center p-1.5 border border-transparent rounded-full shadow-sm text-white bg-red-600 hover:bg-red-700"
>
<.icon name="hero-trash" class="w-3 h-3" />
</button>
</div>
</div>
<% end %>
</li>
<div class="px-6 py-4">
<.category_item category={category} categories={@categories} depth={0} />
</div>
<% end %>
</ul>
</div>
<% end %>
</div>
</div>