defmodule Phoenix.UI.Components.Badge do @moduledoc """ Provides badge component. """ use Phoenix.UI, :component @default_border false @default_color "blue" @default_invisible false @default_position "top_end" @default_variant "standard" @doc """ Renders badge component. ## Examples ``` <.badge content="99+"> <.heroicon name="mail" /> ``` """ @spec badge(Socket.assigns()) :: Rendered.t() def badge(raw) do assigns = raw |> assign_new(:border, fn -> @default_border end) |> assign_new(:color, fn -> @default_color end) |> assign_new(:invisible, fn -> @default_invisible end) |> assign_new(:position, fn -> @default_position end) |> assign_new(:variant, fn -> @default_variant end) |> build_badge_attrs() |> build_wrapper_attrs() ~H"""
<%= render_slot(@inner_block) %> <%= if assigns[:content] do %>
<%= if @variant != "dot" do %> <%= if is_bitstring(@content) do %> <%= @content %> <% else %> <%= render_slot(@content) %> <% end %> <% end %>
<% end %>
""" end ### Wrapper Attrs ########################## defp build_wrapper_attrs(assigns) do wrapper = Map.get(assigns, :wrapper, []) class = build_class(~w( badge-wrapper relative inline-block #{Keyword.get(wrapper, :extend_class)} )) attrs = wrapper |> assigns_to_attributes([:extend_class]) |> Keyword.put_new(:class, class) assign(assigns, :wrapper_attrs, attrs) end ### Badge Attrs ########################## defp build_badge_attrs(assigns) do class = build_class(~w( badge inline-block z-50 absolute text-xs text-white rounded-full text-center transition-all ease-in-out duration-300 #{classes(:border, assigns)} #{classes(:color, assigns)} #{classes(:invisible, assigns)} #{classes(:position, assigns)} #{classes(:variant, assigns)} #{Map.get(assigns, :extend_class)} )) attrs = assigns |> assigns_to_attributes([:color, :content, :id, :position, :variant, :wrapper]) |> Keyword.put_new(:class, class) assign(assigns, :badge_attrs, attrs) end ### CSS Classes ########################## # Border defp classes(:border, %{border: true}), do: "border-2 border-white dark:border-slate-900" # Color defp classes(:color, %{color: color}), do: "bg-#{color}-600" # Color defp classes(:invisible, %{invisible: true}), do: "invisible" # Position defp classes(:position, %{position: "bottom_end"}), do: "top-2/3 left-2/3" defp classes(:position, %{position: "bottom_start"}), do: "top-2/3 right-2/3" defp classes(:position, %{position: "bottom"}), do: "top-2/3 left-1/2 -translate-x-1/2" defp classes(:position, %{position: "left_end"}), do: "right-2/3 top-2/3" defp classes(:position, %{position: "left_start"}), do: "right-2/3 bottom-2/3" defp classes(:position, %{position: "left"}), do: "right-2/3 top-1/2 -translate-y-1/2" defp classes(:position, %{position: "right_end"}), do: "left-2/3 top-2/3" defp classes(:position, %{position: "right_start"}), do: "left-2/3 bottom-2/3" defp classes(:position, %{position: "right"}), do: "left-2/3 top-1/2 -translate-y-1/2" defp classes(:position, %{position: "top_end"}), do: "bottom-2/3 left-2/3" defp classes(:position, %{position: "top_start"}), do: "bottom-2/3 right-2/3" defp classes(:position, %{position: "top"}), do: "bottom-2/3 left-1/2 -translate-x-1/2" # Color defp classes(:variant, %{variant: "dot"}), do: "p-[0.3rem]" defp classes(:variant, %{variant: "standard"}), do: "py-0.5 px-1.5" defp classes(_rule_group, _assigns), do: nil end