Packages
noora
0.83.1
0.85.0
0.84.1
0.84.0
0.83.2
0.83.1
0.83.0
0.82.7
0.82.6
0.82.5
0.82.4
0.82.3
0.82.2
0.82.1
0.82.0
0.81.4
0.81.3
0.81.2
0.81.1
0.81.0
0.80.1
0.80.0
0.79.1
0.79.0
0.78.1
0.78.0
0.77.4
0.77.3
0.77.2
0.77.1
0.77.0
0.76.0
0.75.0
0.74.0
0.73.0
0.72.0
0.71.0
0.70.0
0.69.1
0.69.0
0.68.0
0.67.0
0.66.0
0.65.0
0.64.2
0.64.1
0.64.0
0.63.2
0.63.1
0.63.0
0.62.0
0.61.0
0.60.0
0.59.0
0.58.0
0.57.0
0.56.1
0.56.0
0.55.0
0.54.0
0.53.1
0.53.0
0.52.1
0.52.0
0.51.0
0.50.1
0.50.0
0.49.0
0.48.0
0.47.0
0.46.0
0.45.0
0.44.3
0.44.2
0.44.1
0.44.0
0.43.0
0.42.0
0.41.0
0.40.6
0.40.5
0.40.4
0.40.3
0.40.2
0.40.1
0.40.0
0.39.1
0.39.0
0.38.0
0.37.0
0.36.0
0.35.0
0.34.0
0.33.0
0.32.1
0.32.0
0.31.0
0.30.0
0.29.2
0.29.1
0.29.0
0.28.5
0.28.4
0.28.3
0.28.2
0.28.1
0.28.0
0.27.0
0.26.1
0.26.0
0.25.0
0.24.0
0.23.1
0.23.0
0.22.1
0.22.0
0.21.0
0.20.0
0.19.0
0.18.0
0.17.0
0.16.0
0.15.0
0.14.0
0.13.0
0.12.1
0.12.0
0.11.2
0.11.1
0.11.0
0.10.0
0.9.0
0.8.0
0.7.0
0.6.1
0.6.0
0.5.1
0.5.0
0.4.0
0.3.2
0.3.1
0.3.0
0.2.2
0.2.0
0.1.0
0.1.0-rc.2
0.1.0-rc.1
0.1.0-alpha.6
0.1.0-alpha.5
0.1.0-alpha.4
0.1.0-alpha.3
0.1.0-alpha.2
0.1.0-alpha.1
A component library for Phoenix LiveView applications
Current section
Files
Jump to
Current section
Files
lib/noora/sidebar.ex
defmodule Noora.Sidebar do
@moduledoc """
A flexible sidebar.
## Example
```elixir
<.sidebar>
<.sidebar_item
label="Dashboard"
icon="home"
patch={~p"/dashboard"}
selected={@live_action == :dashboard}
/>
<.sidebar_group
id="products-group"
label="Products"
icon="package"
collapsible={true}
default_open={true}
>
<.sidebar_item
label="All Products"
icon="list"
patch={~p"/products"}
/>
<.sidebar_item
label="Add Product"
icon="plus"
patch={~p"/products/new"}
/>
</.sidebar_group>
</.sidebar>
```
"""
use Phoenix.Component
import Noora.Icon
import Noora.TabMenu
attr(:id, :string, default: "sidebar")
slot(:inner_block, required: true)
def sidebar(assigns) do
~H"""
<div class="noora-sidebar" data-part="sidebar" id={@id} phx-hook="NooraScrollArea">
<div data-part="viewport">
{render_slot(@inner_block)}
</div>
<div id={@id <> "-scrollbar"} data-part="scrollbar" phx-update="ignore">
<div data-part="thumb"></div>
</div>
</div>
"""
end
attr(:id, :string, required: true)
attr(:icon, :string, required: true, doc: "The icon of the group.")
attr(:label, :string, required: true, doc: "The label of the group.")
attr(:collapsible, :boolean, default: true, doc: "Whether the group is collapsible.")
attr(:default_open, :boolean, default: false, doc: "Whether the group is open by default.")
attr(:navigate, :string, default: nil, doc: "Navigates to a LiveView")
attr(:patch, :string, default: nil, doc: "Patches the current LiveView")
attr(:href, :any, default: nil, doc: "Uses traditional browser navigation to the new location")
attr(:selected, :boolean, default: false, doc: "Whether the item is selected.")
attr(:disabled, :boolean, default: false, doc: "Whether the item is disabled.")
attr(:rest, :global)
slot(:inner_block)
def sidebar_group(assigns) do
~H"""
<%= if @collapsible do %>
<div
id={@id}
data-part="collapsible-group"
phx-hook="NooraCollapsible"
data-open={@default_open}
data-persist-key={@id}
data-disabled={@disabled}
{@rest}
>
<div data-part="root">
<%= if @navigate || @patch || @href do %>
<div class="noora-tab-menu-vertical" data-part="header" data-selected={@selected}>
<.link navigate={@navigate} patch={@patch} href={@href} data-part="link">
<div data-part="icon-left"><.icon name={@icon} /></div>
<span data-part="label">{@label}</span>
</.link>
<button type="button" data-part="trigger" aria-label={"Toggle #{@label}"}>
<div data-part="indicator">
<.icon
id={@id <> "-indicator"}
name="chevron_right"
active_name="chevron_down"
transition="crossfade_rotate"
active_state="open"
/>
</div>
</button>
</div>
<% else %>
<button
type="button"
class="noora-tab-menu-vertical"
data-part="trigger"
data-selected={@selected}
disabled={@disabled}
>
<div data-part="icon-left"><.icon name={@icon} /></div>
<span data-part="label">{@label}</span>
<div data-part="icon-right">
<div data-part="indicator">
<.icon
id={@id <> "-indicator"}
name="chevron_right"
active_name="chevron_down"
transition="crossfade_rotate"
active_state="open"
/>
</div>
</div>
</button>
<% end %>
<div data-part="content" hidden={!@default_open}>
{render_slot(@inner_block)}
</div>
</div>
</div>
<% else %>
<div id={@id} data-part="group" {@rest}>
<span data-part="group-label">{@label}</span>
{render_slot(@inner_block)}
</div>
<% end %>
"""
end
attr(:label, :string, required: true, doc: "The label of the item.")
attr(:icon, :string, required: true, doc: "The icon of the item.")
attr(:selected, :boolean, default: false, doc: "Whether the item is selected.")
attr(:navigate, :string, default: nil, doc: "Navigates to a LiveView")
attr(:patch, :string, default: nil, doc: "Patches the current LiveView")
attr(:href, :any, default: nil, doc: "Uses traditional browser navigation to the new location")
attr(:external, :boolean, default: false, doc: "Whether the item points to an external resource.")
attr(:rest, :global)
def sidebar_item(assigns) do
~H"""
<.link navigate={@navigate} patch={@patch} href={@href} data-part="item" {@rest}>
<.tab_menu_vertical label={@label} data-selected={@selected}>
<:icon_left>
<.icon name={@icon} />
</:icon_left>
<:icon_right :if={@external}>
<.external_link />
</:icon_right>
</.tab_menu_vertical>
</.link>
"""
end
end