defmodule PetalComponents.Button do
use Phoenix.Component
alias PetalComponents.Loading
alias PetalComponents.Link
alias PetalComponents.Icon
import PetalComponents.Helpers
require Logger
attr(:size, :string, default: "md", values: ["xs", "sm", "md", "lg", "xl"], doc: "button sizes")
attr(:variant, :string,
default: "solid",
values: ["solid", "outline", "inverted", "shadow"],
doc: "button variant"
)
attr(:color, :string,
default: "primary",
values: [
"primary",
"secondary",
"info",
"success",
"warning",
"danger",
"gray",
"pure_white",
"white",
"light"
],
doc: "button color"
)
attr(:to, :string, default: nil, doc: "link path")
attr(:loading, :boolean, default: false, doc: "indicates a loading state")
attr(:disabled, :boolean, default: false, doc: "indicates a disabled state")
attr(:icon, :atom, default: nil, doc: "name of a Heroicon at the front of the button")
attr(:with_icon, :boolean, default: false, doc: "adds some icon base classes")
attr(:link_type, :string,
default: "button",
values: ["a", "live_patch", "live_redirect", "button"]
)
attr(:class, :string, default: "", doc: "CSS class")
attr(:label, :string, default: nil, doc: "labels your button")
attr(:rest, :global,
include: ~w(method download hreflang ping referrerpolicy rel target type value name form)
)
slot(:inner_block, required: false)
def button(assigns) do
assigns =
assigns
|> assign(:classes, button_classes(assigns))
~H"""
<Link.a to={@to} link_type={@link_type} class={@classes} disabled={@disabled} {@rest}>
<%= if @loading do %>
<Loading.spinner show={true} size_class={get_spinner_size_classes(@size)} />
<% else %>
<%= if @icon do %>
<Icon.icon name={@icon} mini class={get_spinner_size_classes(@size)} />
<% end %>
<% end %>
<%= render_slot(@inner_block) || @label %>
</Link.a>
"""
end
attr(:size, :string, default: "sm", values: ["xs", "sm", "md", "lg", "xl"])
attr(:color, :string,
default: "gray",
values: ["primary", "secondary", "info", "success", "warning", "danger", "gray"]
)
attr(:to, :string, default: nil, doc: "link path")
attr(:loading, :boolean, default: false, doc: "indicates a loading state")
attr(:disabled, :boolean, default: false, doc: "indicates a disabled state")
attr(:with_icon, :boolean, default: false, doc: "adds some icon base classes")
attr(:link_type, :string,
default: "button",
values: ["a", "live_patch", "live_redirect", "button"]
)
attr(:class, :string, default: "", doc: "CSS class")
attr(:tooltip, :string, default: nil, doc: "tooltip text")
attr(:rest, :global,
include: ~w(method download hreflang ping referrerpolicy rel target type value name form)
)
slot(:inner_block, required: false)
def icon_button(assigns) do
~H"""
<Link.a
to={@to}
link_type={@link_type}
class={
build_class([
"pc-icon-button",
get_disabled_classes(@disabled),
get_icon_button_background_color_classes(@color),
get_icon_button_color_classes(@color),
get_icon_button_size_classes(@size),
@class
])
}
disabled={@disabled}
{@rest}
>
<div class={@tooltip && "relative group/pc-icon-button flex flex-col items-center"}>
<%= if @loading do %>
<Loading.spinner show={true} size_class={get_icon_button_spinner_size_classes(@size)} />
<% else %>
<%= render_slot(@inner_block) %>
<div :if={@tooltip} role="tooltip" class="pc-icon-button__tooltip">
<span class="pc-icon-button__tooltip__text">
<%= @tooltip %>
</span>
<div class="pc-icon-button__tooltip__arrow"></div>
</div>
<% end %>
</div>
</Link.a>
"""
end
defp button_classes(opts) do
opts = %{
size: opts[:size] || "md",
variant: opts[:variant] || "solid",
color: opts[:color] || "primary",
loading: opts[:loading] || false,
disabled: opts[:disabled] || false,
with_icon: opts[:with_icon] || opts[:icon] || false,
user_added_classes: opts[:class] || ""
}
color_css = get_color_classes(opts)
size_css = "pc-button--#{opts.size}"
loading_css = if opts[:loading], do: "pc-button--loading", else: ""
icon_css = if opts[:with_icon], do: "pc-button--with-icon", else: ""
[
color_css,
size_css,
loading_css,
get_disabled_classes(opts[:disabled]),
icon_css,
"pc-button",
opts.user_added_classes
]
|> build_class()
end
defp get_color_classes(%{color: "primary", variant: variant}) do
case variant do
"outline" ->
"pc-button--primary-outline"
"inverted" ->
"pc-button--primary-inverted"
"shadow" ->
"pc-button--primary-shadow"
_ ->
"pc-button--primary"
end
end
defp get_color_classes(%{color: "secondary", variant: variant}) do
case variant do
"outline" ->
"pc-button--secondary-outline"
"inverted" ->
"pc-button--secondary-inverted"
"shadow" ->
"pc-button--secondary-shadow"
_ ->
"pc-button--secondary"
end
end
defp get_color_classes(%{color: "white", variant: variant}) do
case variant do
"outline" ->
"pc-button--white-outline"
"inverted" ->
"pc-button--white-inverted"
"shadow" ->
"pc-button--white-shadow"
_ ->
"pc-button--white"
end
end
defp get_color_classes(%{color: "pure_white", variant: variant}) do
case variant do
_ ->
"pc-button--pure-white"
end
end
defp get_color_classes(%{color: "info", variant: variant}) do
case variant do
"outline" ->
"pc-button--info-outline"
"inverted" ->
"pc-button--info-inverted"
"shadow" ->
"pc-button--info-shadow"
_ ->
"pc-button--info"
end
end
defp get_color_classes(%{color: "success", variant: variant}) do
case variant do
"outline" ->
"pc-button--success-outline"
"inverted" ->
"pc-button--success-inverted"
"shadow" ->
"pc-button--success-shadow"
_ ->
"pc-button--success"
end
end
defp get_color_classes(%{color: "warning", variant: variant}) do
case variant do
"outline" ->
"pc-button--warning-outline"
"inverted" ->
"pc-button--warning-inverted"
"shadow" ->
"pc-button--warning-shadow"
_ ->
"pc-button--warning"
end
end
defp get_color_classes(%{color: "danger", variant: variant}) do
case variant do
"outline" ->
"pc-button--danger-outline"
"inverted" ->
"pc-button--danger-inverted"
"shadow" ->
"pc-button--danger-shadow"
_ ->
"pc-button--danger"
end
end
defp get_color_classes(%{color: "gray", variant: variant}) do
case variant do
"outline" ->
"pc-button--gray-outline"
"inverted" ->
"pc-button--gray-inverted"
"shadow" ->
"pc-button--gray-shadow"
_ ->
"pc-button--gray"
end
end
defp get_color_classes(%{color: "light", variant: variant}) do
case variant do
"outline" ->
"pc-button--light-outline"
"inverted" ->
"pc-button--light-inverted"
"shadow" ->
"pc-button--light-shadow"
_ ->
"pc-button--light"
end
end
defp get_spinner_size_classes("xs"), do: "pc-button__spinner-icon--xs"
defp get_spinner_size_classes("sm"), do: "pc-button__spinner-icon--sm"
defp get_spinner_size_classes("md"), do: "pc-button__spinner-icon--md"
defp get_spinner_size_classes("lg"), do: "pc-button__spinner-icon--lg"
defp get_spinner_size_classes("xl"), do: "pc-button__spinner-icon--xl"
def get_icon_button_size_classes("xs"), do: "pc-icon-button--xs"
def get_icon_button_size_classes("sm"), do: "pc-icon-button--sm"
def get_icon_button_size_classes("md"), do: "pc-icon-button--md"
def get_icon_button_size_classes("lg"), do: "pc-icon-button--lg"
def get_icon_button_size_classes("xl"), do: "pc-icon-button--xl"
def get_icon_button_spinner_size_classes("xs"), do: "pc-icon-button-spinner--xs"
def get_icon_button_spinner_size_classes("sm"), do: "pc-icon-button-spinner--sm"
def get_icon_button_spinner_size_classes("md"), do: "pc-icon-button-spinner--md"
def get_icon_button_spinner_size_classes("lg"), do: "pc-icon-button-spinner--lg"
def get_icon_button_spinner_size_classes("xl"), do: "pc-icon-button-spinner--xl"
defp get_icon_button_color_classes("primary"), do: "pc-icon-button--primary"
defp get_icon_button_color_classes("secondary"),
do: "pc-icon-button--secondary"
defp get_icon_button_color_classes("gray"), do: "pc-icon-button--gray"
defp get_icon_button_color_classes("info"), do: "pc-icon-button--primary"
defp get_icon_button_color_classes("success"), do: "pc-icon-button--success"
defp get_icon_button_color_classes("warning"), do: "pc-icon-button--warning"
defp get_icon_button_color_classes("danger"), do: "pc-icon-button--danger"
defp get_icon_button_background_color_classes("primary"),
do: "pc-icon-button-bg--primary"
defp get_icon_button_background_color_classes("secondary"),
do: "pc-icon-button-bg--secondary"
defp get_icon_button_background_color_classes("gray"),
do: "pc-icon-button-bg--gray"
defp get_icon_button_background_color_classes("info"),
do: "pc-icon-button-bg--info"
defp get_icon_button_background_color_classes("success"),
do: "pc-icon-button-bg--success"
defp get_icon_button_background_color_classes("warning"),
do: "pc-icon-button-bg--warning"
defp get_icon_button_background_color_classes("danger"),
do: "pc-icon-button-bg--danger"
defp get_disabled_classes(true), do: "pc-button--disabled"
defp get_disabled_classes(false), do: ""
end