Current section
Files
Jump to
Current section
Files
lib/components/buttons.ex
defmodule SigmaKit.Components.Buttons do
use Phoenix.LiveComponent
import SigmaKit.Components.Icons
import SigmaKit.Components.Popups, only: [popover: 1]
@doc """
Renders a simple button component.
"""
attr :class, :any, default: nil, doc: "Additional CSS classes to apply to the button."
attr :primary, :boolean, default: false, doc: "Apply the primary style to the button."
attr :dark, :boolean, default: false, doc: "Apply a dark style to the button."
attr :light, :boolean, default: false, doc: "Apply the light style to the button."
attr :danger, :boolean, default: false, doc: "Apply the danger style to the button."
attr :inline, :boolean, default: false, doc: "Apply the inline style to the button."
attr :rest, :global,
include: ~w(type disabled form name value),
doc: "Additional attributes to apply to the button."
slot :inner_block, required: true, doc: "The content to render inside the button."
def button(assigns) do
~H"""
<button
class={[
"phx-submit-loading:opacity-75 rounded-lg transition-all",
"text-sm font-semibold leading-6",
!@inline && "py-2 px-3",
!@primary && !@light && !@danger && !@dark &&
"bg-white hover:bg-gradient-to-t from-gray-100 to-20% to-white shadow border border-gray-200 hover:border-gray-300 text-zinc-600 hover:text-zinc-800",
@dark && "bg-zinc-900 hover:bg-zinc-700 text-white active:text-white/80",
@primary && "bg-blue-600 hover:bg-blue-800 text-white",
@light && "bg-gray-200 hover:bg-gray-300 text-zinc-800",
@danger && "bg-red-700 text-zinc-50 hover:bg-red-900",
@inline &&
"px-3 py-1",
@class
]}
{@rest}
>
{render_slot(@inner_block)}
</button>
"""
end
@doc """
Renders a toggle switch with icons on the left and right sides.
"""
attr :left_icon, :string,
required: true,
doc: "The name of the icon to display on the left side of the toggle switch."
attr :right_icon, :string,
required: true,
doc: "The name of the icon to display on the right side of the toggle switch."
attr :event, :string,
required: true,
doc: "The event name triggered when the toggle switch is clicked."
attr :target, :any, default: nil, doc: "The target for the `phx-click` event."
attr :left, :boolean, required: true, doc: "Determines if the toggle is in the 'left' position."
attr :right, :boolean,
required: true,
doc: "Determines if the toggle is in the 'right' position."
def icon_toggle_switch(assigns) do
~H"""
<div class="flex gap-2 items-center cursor-pointer" phx-click={@event} phx-target={@target}>
<.icon name={@left_icon} class={["w-5 h-5", !@left && "text-zinc-300"]} />
<div class={[
"h-6 w-12 bg-gray-100 shadow-inner rounded-full flex items-center px-2",
@left && "justify-start",
@right && "justify-end",
!@left && !@right && "justify-center"
]}>
<div class="w-4 h-4 rounded-full bg-blue-500"></div>
</div>
<.icon name={@right_icon} class={["w-5 h-5", !@right && "text-zinc-300"]} />
</div>
"""
end
@doc """
Renders a dropdown button with a customizable label and a list of actions.
"""
attr :label, :string, doc: "The label displayed on the dropdown button."
attr :id, :string, required: true, doc: "A unique identifier for the dropdown component."
attr :inline, :boolean, default: true, doc: "Apply the inline style to the dropdown button."
slot :action, doc: "A dropdwn menu item" do
attr :label, :string, doc: "The label for the menu item."
attr :icon, :string, doc: "The name of the icon to display"
attr :event, :string, doc: "The event triggered when the menu item is clicked."
attr :target, :any, doc: "The target for the `phx-click` event."
attr :value, :any, doc: "The value passed with the `phx-click` event."
end
def dropdown(assigns) do
~H"""
<.popover id={@id} placement="bottom" trigger_click nopad minwidth>
<:trigger>
<.button inline={@inline} type="button">
{@label}
<.icon name="hero-chevron-down" class="ms-2 h-3 w-3" />
</.button>
</:trigger>
<ul class="select-none">
<li :for={action <- @action}>
<div
phx-click={action[:event]}
phx-target={action[:target]}
phx-value-value={action[:value]}
class="block text-sm bg-white hover:text-zinc-800 text-zinc-600 text-nowrap font-medium flex items-center transition-all relative cursor-pointer border-l-4 border-gray-400 hover:border-gray-600"
>
<div :if={action[:icon]} class="px-2 py-2 ">
<.icon name={action.icon} class="w-4 h-4" />
</div>
<div class="py-2 px-2">
{action.label}
</div>
</div>
</li>
</ul>
</.popover>
"""
end
attr :id, :string, required: true
attr :class, :any, default: nil
slot :action, doc: "overflow items presented as a dropdown menu" do
attr :label, :string, doc: "The label for the menu item"
attr :event, :string, doc: "The phx-click event for the menu item"
attr :value, :string, doc: "The phx-value for the menu item"
attr :value_id, :string, doc: "The phx-value-id for the menu item"
attr :target, :string, doc: "The phx-target for the menu item"
attr :icon, :string, doc: "The icon for the menu item"
end
def action_dropdown(assigns) do
~H"""
<.popover id={@id} placement="bottom" trigger_click nopad minwidth>
<:trigger>
<button class={["bg-white px-3 hover:bg-gray-100", @class]} type="button">
<.icon name="hero-ellipsis-horizontal" class="h-4 w-4" />
</button>
</:trigger>
<ul class="">
<li :for={action <- @action}>
<div
phx-click={action[:event]}
phx-target={action[:target]}
phx-value-value={action[:value]}
phx-value-id={action[:value_id]}
class="px-2 block text-sm bg-white hover:bg-gray-100 text-zinc-800 text-nowrap font-medium flex items-center transition-all relative cursor-pointer border-l-4 border-gray-400 hover:border-gray-600"
>
<div :if={action[:icon]} class="py-2 px-1">
<.icon name={action.icon} class="w-4 h-4 me-2" />
</div>
<div class="py-2 px-2">
{action.label}
</div>
</div>
</li>
</ul>
</.popover>
"""
end
end