fix(elixir): show deeply nested categories
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user