Packages
mishka_chelekom
0.0.2
0.0.10-alpha.5
0.0.10-alpha.4
0.0.10-alpha.3
0.0.10-alpha.2
0.0.10-alpha.1
0.0.9
0.0.9-rc.2
0.0.9-rc.1
0.0.9-beta.5
0.0.9-beta.4
0.0.9-beta.3
0.0.9-beta.2
0.0.9-beta.1
0.0.9-alpha.20
0.0.9-alpha.18
0.0.9-alpha.17
0.0.9-alpha.16
0.0.9-alpha.15
0.0.9-alpha.14
0.0.9-alpha.13
0.0.9-alpha.12
0.0.9-alpha.11
0.0.9-alpha.10
0.0.9-alpha.9
0.0.9-alpha.8
0.0.9-alpha.7
0.0.9-alpha.6
0.0.9-alpha.5
0.0.9-alpha.4
0.0.9-alpha.3
0.0.9-alpha.2
0.0.9-alpha.1
0.0.8
0.0.8-rc.2
0.0.8-rc.1
0.0.8-beta.5
0.0.8-beta.4
0.0.8-beta.3
0.0.8-beta.2
0.0.8-beta.1
0.0.8-alpha.4
0.0.8-alpha.3
0.0.8-alpha.2
0.0.8-alpha.1
0.0.7
0.0.6
0.0.6-alpha.2
0.0.6-alpha.1
0.0.5
0.0.5-beta.2
0.0.5-beta.1
0.0.5-alpha.12
0.0.5-alpha.11
0.0.5-alpha.10
0.0.5-alpha.9
0.0.5-alpha.8
0.0.5-alpha.7
0.0.5-alpha.6
0.0.5-alpha.5
0.0.5-alpha.4
0.0.5-alpha.3
0.0.5-alpha.2
0.0.5-alpha.1
0.0.4
0.0.4-beta.3
0.0.4-beta.2
0.0.4-beta.1
0.0.4-alpha.9
0.0.4-alpha.8
0.0.4-alpha.7
0.0.4-alpha.6
0.0.4-alpha.5
0.0.4-alpha.4
0.0.4-alpha.3
0.0.4-alpha.2
0.0.4-alpha.1
0.0.3
0.0.3-alpha.3
0.0.3-alpha.2
0.0.3-alpha.1
0.0.2
0.0.2-rc.2
0.0.2-rc.1
0.0.2-beta.4
0.0.2-beta.3
0.0.2-beta.2
0.0.2-beta.1
0.0.2-alpha.3
0.0.2-alpha.2
0.0.2-alpha.1
0.0.1
Mishka Chelekom is a fully featured components and UI kit library for Phoenix & Phoenix LiveView
Current section
Files
Jump to
Current section
Files
priv/components/menu.eex
defmodule <%= @module %> do
@moduledoc """
The `<%= @module %>` module is designed to render a hierarchical menu structure in
Phoenix LiveView applications. It provides a versatile menu component capable of
handling both simple and complex navigation systems with nested sub-menus.
This module supports dynamic configuration of menu items through a list of maps,
allowing for a wide range of customization options. Menu items can be rendered as
standalone buttons or as expandable accordions containing nested sub-menus.
The `MishkaChelekom.Menu` is ideal for creating multi-level navigation menus in
applications with complex information architectures.
The component integrates smoothly with other components from the `MishkaChelekom`
library, such as `accordion` and `button_link`, to offer a consistent and cohesive
UI experience. It also includes support for various padding and spacing options to
control the layout and appearance of the menu.
"""
use Phoenix.Component
import <%= inspect(@web_module) %>.Components.Accordion, only: [accordion: 1]
import <%= inspect(@web_module) %>.Components.Button, only: [button_link: 1]
@doc """
Renders a customizable `menu` component that can include menu items as a list of maps or use
additional slots to define nested content.
It supports both direct menu items and nested accordion submenus.
## Examples
```elixir
<.menu>
<li>
<.button_link
navigate="/"
size="extra_small"
color="misc"
variant="unbordered"
rounded="large"
class="w-full"
display="flex"
icon_class="size-5"
icon="hero-home"
font_weight="font-bold"
>
Dashboard
</.button_link>
</li>
<li>
<.button_link
size="extra_small"
color="misc"
variant="unbordered"
rounded="large"
class="w-full"
display="flex"
navigate="/examples/footer"
icon_class="size-5"
icon="hero-server"
>
Footer
</.button_link>
</li>
<li>
<.accordion
padding="none"
id="accordion1"
size="extra_small"
rounded="large"
color="misc"
variant="menu"
>
<:item title="Menu item" icon_class="size-5" icon="hero-bookmark">
<ul class="pl-5 space-y-3 mt-3">
<.button_link
navigate="/examples/indicator"
size="extra_small"
color="misc"
variant="unbordered"
rounded="large"
class="w-full"
display="flex"
icon_class="size-5"
icon="hero-scissors"
>
Indicator
</.button_link>
<.button_link
navigate="/examples/image"
size="extra_small"
color="misc"
variant="unbordered"
rounded="large"
class="w-full"
display="flex"
icon_class="size-5"
icon="hero-scale"
>
Image
</.button_link>
<.button_link
navigate="/examples/rating"
size="extra_small"
color="misc"
variant="unbordered"
rounded="large"
class="w-full"
display="flex"
icon_class="size-5"
icon="hero-building-storefront"
>
Rating
</.button_link>
<.accordion
variant="menu"
padding="none"
size="extra_small"
rounded="large"
color="misc"
id="accordion2"
>
<:item title="Invoice" icon_class="size-5" icon="hero-building-storefront">
<ul class="pl-5 space-y-3 mt-3">
<.button_link
navigate="/examples/popover"
size="extra_small"
color="misc"
variant="unbordered"
rounded="large"
class="w-full"
display="flex"
icon_class="size-5"
icon="hero-bolt"
>
Popover
</.button_link>
<.button_link
navigate="/examples/overlay"
size="extra_small"
color="misc"
variant="unbordered"
rounded="large"
class="w-full"
display="flex"
icon_class="size-5"
icon="hero-shopping-bag"
>
Overlay
</.button_link>
</ul>
</:item>
</.accordion>
</ul>
</:item>
</.accordion>
</li>
<li>
<.button_link
navigate="/examples/modal"
size="extra_small"
color="misc"
variant="unbordered"
rounded="large"
class="w-full"
display="flex"
icon_class="size-5"
icon="hero-bell"
>
Modal
</.button_link>
</li>
<li>
<.button_link
navigate="/examples/list"
size="extra_small"
color="misc"
variant="unbordered"
rounded="large"
class="w-full"
display="flex"
icon_class="size-5"
icon="hero-cake"
>
List
</.button_link>
</li>
</.menu>
```
### It can be used as list of map
```elixir
list_menues = [
%{
id: "Dashaboard",
navigate: "/",
title: "Dashaboard",
size: "extra_small",
color: "misc",
variant: "unbordered",
rounded: "large",
class: "w-full",
display: "flex",
icon_class: "size-5",
icon: "hero-home",
active: true
},
%{
id: "Footer",
navigate: "/examples/footer",
title: "Footer",
size: "extra_small",
color: "misc",
variant: "unbordered",
rounded: "large",
class: "w-full",
display: "flex",
icon_class: "size-5",
icon: "hero-server"
},
%{
id: "Menu-item",
title: "Menu item",
padding: "pl-5 space-y-3 mt-3",
size: "extra_small",
rounded: "large",
color: "misc",
variant: "menu",
icon: "hero-bookmark",
icon_class: "size-5",
sub_items: [
%{
navigate: "/examples/indicator",
title: "Indicator",
size: "extra_small",
color: "misc",
variant: "unbordered",
rounded: "large",
class: "w-full",
display: "flex",
icon_class: "size-5",
icon: "hero-scissors"
},
%{
navigate: "/examples/image",
title: "Image",
size: "extra_small",
color: "misc",
variant: "unbordered",
rounded: "large",
class: "w-full",
display: "flex",
icon_class: "size-5",
icon: "hero-scale"
},
%{
navigate: "/examples/rating",
title: "Rating",
size: "extra_small",
color: "misc",
variant: "unbordered",
rounded: "large",
class: "w-full",
display: "flex",
icon_class: "size-5",
icon: "hero-building-storefront"
},
%{
id: "Invoice",
title: "Invoice",
variant: "menu",
padding: "pl-5 space-y-3 mt-3",
size: "extra_small",
rounded: "large",
color: "misc",
icon: "hero-bookmark",
icon_class: "size-5",
sub_items: [
%{
navigate: "/examples/popover",
title: "Popover",
size: "extra_small",
color: "misc",
variant: "unbordered",
rounded: "large",
class: "w-full",
display: "flex",
icon_class: "size-5",
icon: "hero-bolt"
},
%{
navigate: "/examples/overlay",
title: "Overlay",
size: "extra_small",
color: "misc",
variant: "unbordered",
rounded: "large",
class: "w-full",
display: "flex",
icon_class: "size-5",
icon: "hero-shopping-bag"
}
]
}
]
},
%{
navigate: "/examples/modal",
title: "Modal",
size: "extra_small",
color: "misc",
variant: "unbordered",
rounded: "large",
class: "w-full",
display: "flex",
icon_class: "size-5",
icon: "hero-bell"
}
]
<.menu menu_items={@list_menues} />
```
"""
@doc type: :component
attr :id, :string,
default: nil,
doc: "A unique identifier is used to manage state and interaction"
attr :class, :string, default: nil, doc: "Custom CSS class for additional styling"
attr :menu_items, :list, default: [], doc: "Determines menu items as a list of maps"
attr :space, :string, default: "small", doc: "Space between items"
attr :padding, :string, default: "small", doc: "Determines padding for items"
slot :inner_block,
doc:
"Global attributes can define defaults which are merged with attributes provided by the caller"
attr :rest, :global,
doc:
"Global attributes can define defaults which are merged with attributes provided by the caller"
def menu(assigns) do
~H"""
<ul
id={@id}
class={[
padding_size(@padding),
space_class(@space),
@class
]}
{@rest}
>
<li :for={menu_item <- @menu_items}>
<.button_link
:if={Map.get(menu_item, :sub_items, []) == []}
font_weight={menu_item[:active] && "font-bold"}
{menu_item}
/>
<.accordion
:if={Map.get(menu_item, :sub_items, []) != []}
padding="none"
{Map.drop(menu_item, [:sub_items, :padding])}
>
<:item title={menu_item[:title]} icon_class={menu_item[:icon_class]} icon={menu_item[:icon]}>
<.menu
id={menu_item[:id]}
class={menu_item[:padding]}
menu_items={Map.get(menu_item, :sub_items, [])}
/>
</:item>
</.accordion>
</li>
{render_slot(@inner_block)}
</ul>
"""
end
<%= if is_nil(@padding) or "extra_small" in @padding do %>
defp padding_size("extra_small"), do: "p-2"
<% end %>
<%= if is_nil(@padding) or "small" in @padding do %>
defp padding_size("small"), do: "p-2.5"
<% end %>
<%= if is_nil(@padding) or "medium" in @padding do %>
defp padding_size("medium"), do: "p-3"
<% end %>
<%= if is_nil(@padding) or "large" in @padding do %>
defp padding_size("large"), do: "p-3.5"
<% end %>
<%= if is_nil(@padding) or "extra_large" in @padding do %>
defp padding_size("extra_large"), do: "p-4"
<% end %>
<%= if is_nil(@padding) or "none" in @padding do %>
defp padding_size("none"), do: "p-0"
<% end %>
defp padding_size(params) when is_binary(params), do: params
<%= if is_nil(@space) or "none" in @space do %>
defp space_class("none"), do: nil
<% end %>
<%= if is_nil(@space) or "extra_small" in @space do %>
defp space_class("extra_small"), do: "space-y-2"
<% end %>
<%= if is_nil(@space) or "small" in @space do %>
defp space_class("small"), do: "space-y-3"
<% end %>
<%= if is_nil(@space) or "medium" in @space do %>
defp space_class("medium"), do: "space-y-4"
<% end %>
<%= if is_nil(@space) or "large" in @space do %>
defp space_class("large"), do: "space-y-5"
<% end %>
<%= if is_nil(@space) or "extra_large" in @space do %>
defp space_class("extra_large"), do: "space-y-6"
<% end %>
defp space_class(params) when is_binary(params), do: params
end