Recently I created a simple library to provide function components to render lucide icons, formally feather icons. My complete code can be found here.
Then in my application, I have these function components:
- Navbar
attr :conn, :any
attr :hidden?, :boolean, default: true
def navbar(assigns) do
~H"""
<nav class="navbar bg-white w-full">
<div class="navbar-start p-1 w-3/4 flex justify-between lg:hidden">
<div class="dropdown">
<label tabindex="0">
<!-- hamburguer icon -->
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-12 w-12"
fill="none"
viewBox="0 0 24 24"
stroke="#F8961E"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M4 6h16M4 12h8m-8 6h16"
/>
</svg>
</label>
<ul
tabindex="0"
class="menu menu-compact dropdown-content dropdown-left mt-3 p-2 shadow bg-white rounded-box w-52"
>
<.menu_links current_user={@conn.assigns.current_user} path={@conn.path_info} />
</ul>
</div>
<.menu_logo hidden?={@hidden?} />
</div>
<div class="navbar-center container hidden lg:flex lg:justify-center">
<ul class="menu menu-horizontal p-0">
<.menu_logo hidden?={false} />
<.menu_links current_user={@conn.assigns.current_user} path={@conn.path_info} />
</ul>
</div>
</nav>
"""
end
- Menu links
attr :path, :string
attr :current_user, Pescarte.Accounts.Models.User, default: nil
defp menu_links(assigns) do
~H"""
<%= if @current_user do %>
<%= for item <- authenticated_menu() do %>
<.menu_item
path={item.path}
label={item.label}
method={item.method}
current?={is_current_path?(@conn, item.path)}
>
<%= render_slot(item.icon) %>
</.menu_item>
<% end %>
<.link type="button" navigate={~p"/acessar"}>
Acessar
</.link>
<% else %>
<%= for item <- guest_menu() do %>
<.menu_item
path={item.path}
label={item.label}
method={item.method}
current?={is_current_path?(@path, item.path)}
>
<Lucideicons.{item.icon} />
</.menu_item>
<% end %>
<.link type="button" navigate={~p"/acessar"}>
Acessar
</.link>
<% end %>
"""
end
defp is_current_path?(path_info, to) do
# get from %Plug.Conn{}
path = Enum.join(path_info, "/")
to =~ path
end
defp guest_menu do
[
%{path: "/", label: "Home", method: :get, icon: &Lucideicons.home/1},
%{path: "/pesquisa", label: "Pesquisa", method: :get, icon: "file"},
%{path: "/biblioteca", label: "Biblioteca", method: :get, icon: "book"},
%{
path: "/agenda_socioambiental",
label: "Agenda Socioambiental",
method: :get,
icon: "agenda"
}
]
end
defp authenticated_menu do
[
%{path: "/app/dashboard", label: "Home", method: :get, icon: "home"},
%{path: "/app/pesquisadores", label: "Pesquisadores", method: :get, icon: "accounts"},
%{path: "/app/relatorios", label: "RelatĂłrios", method: :get, icon: "file"},
%{path: "/app/agenda", label: "Agenda", method: :get, icon: "agenda"},
%{path: "/app/mensagens", label: "Mensagens", method: :get, icon: "message"}
]
end
- Menu Item
attr :path, :string
attr :method, :string, default: "get"
attr :current?, :boolean, default: false
attr :label, :string
slot :icon, required: false
defp menu_item(assigns) do
~H"""
<li class="menu-item">
<.link navigate={@path} method={@method} class={@current? && "current"}>
<%= if assigns[:icon], do: render_slot(@icon) %>
<%= @label %>
</.link>
</li>
"""
end
Before I built the lucide icons library, I used to render icons manually. Still, for now, I want to render those function components provided by my library, however, I don’t know if it’s possible.