defmodule PhoenixKitWeb.Components.Dashboard.Badge do @moduledoc """ Badge component for dashboard tab indicators. Renders various badge types with support for: - Count badges (numeric) - Dot indicators - Status badges - "New" indicators - Custom text badges - Pulse and other animations """ use Phoenix.Component alias PhoenixKit.Dashboard.Badge, as: BadgeStruct @doc """ Renders a dashboard badge. ## Attributes - `badge` - The Badge struct or nil - `class` - Additional CSS classes ## Examples <.dashboard_badge badge={@tab.badge} /> <.dashboard_badge badge={Badge.count(5)} /> """ attr :badge, :any, default: nil attr :class, :string, default: "" def dashboard_badge(assigns) do ~H""" <%= if @badge && BadgeStruct.visible?(@badge) do %> <%= case @badge.type do %> <% :dot -> %> <.dot_badge badge={@badge} class={@class} /> <% :count -> %> <.count_badge badge={@badge} class={@class} /> <% :status -> %> <.status_badge badge={@badge} class={@class} /> <% :new -> %> <.new_badge badge={@badge} class={@class} /> <% :text -> %> <.text_badge badge={@badge} class={@class} /> <% :compound -> %> <.compound_badge badge={@badge} class={@class} /> <% _ -> %> <.count_badge badge={@badge} class={@class} /> <% end %> <% end %> """ end @doc """ Renders a count badge with optional max value display. """ attr :badge, :any, required: true attr :class, :string, default: "" def count_badge(assigns) do value = BadgeStruct.display_value(assigns.badge) color_class = BadgeStruct.color_class(assigns.badge) assigns = assigns |> assign(:value, value) |> assign(:color_class, color_class) ~H""" {@value} """ end @doc """ Renders a dot indicator badge. """ attr :badge, :any, required: true attr :class, :string, default: "" def dot_badge(assigns) do color_class = BadgeStruct.dot_color_class(assigns.badge) assigns = assign(assigns, :color_class, color_class) ~H""" """ end @doc """ Renders a status badge with value and color. """ attr :badge, :any, required: true attr :class, :string, default: "" def status_badge(assigns) do value = BadgeStruct.display_value(assigns.badge) color_class = BadgeStruct.color_class(assigns.badge) assigns = assigns |> assign(:value, value) |> assign(:color_class, color_class) ~H""" String.replace("badge-", "text-")}> {String.capitalize(to_string(@value))} """ end @doc """ Renders a "New" indicator badge. """ attr :badge, :any, required: true attr :class, :string, default: "" def new_badge(assigns) do color_class = BadgeStruct.color_class(assigns.badge) assigns = assign(assigns, :color_class, color_class) ~H""" New """ end @doc """ Renders a custom text badge. """ attr :badge, :any, required: true attr :class, :string, default: "" def text_badge(assigns) do value = BadgeStruct.display_value(assigns.badge) color_class = BadgeStruct.color_class(assigns.badge) assigns = assigns |> assign(:value, value) |> assign(:color_class, color_class) ~H""" {@value} """ end @doc """ Renders a compound badge with multiple colored segments. Supports three styles: - `:text` - Colored text values with separator (default) - `:blocks` - Colored background pills side by side - `:dots` - Colored dots with numbers """ attr :badge, :any, required: true attr :class, :string, default: "" def compound_badge(assigns) do segments = BadgeStruct.visible_segments(assigns.badge) style = assigns.badge.compound_style || :text separator = assigns.badge.separator || "/" assigns = assigns |> assign(:segments, segments) |> assign(:style, style) |> assign(:separator, separator) ~H""" <%= case @style do %> <% :text -> %> <.compound_text_style segments={@segments} separator={@separator} /> <% :blocks -> %> <.compound_blocks_style segments={@segments} /> <% :dots -> %> <.compound_dots_style segments={@segments} /> <% _ -> %> <.compound_text_style segments={@segments} separator={@separator} /> <% end %> """ end # Text style: "10 / 5 / 2" with colored text defp compound_text_style(assigns) do ~H""" <%= for {segment, index} <- Enum.with_index(@segments) do %> <%= if index > 0 do %> {@separator} <% end %> {segment[:value] || segment["value"]} <%= if segment[:label] || segment["label"] do %> {segment[:label] || segment["label"]} <% end %> <% end %> """ end # Blocks style: colored background pills defp compound_blocks_style(assigns) do ~H""" <%= for segment <- @segments do %> {segment[:value] || segment["value"]} <% end %> """ end # Dots style: colored dots with numbers defp compound_dots_style(assigns) do ~H""" <%= for segment <- @segments do %> {segment[:value] || segment["value"]} <% end %> """ end # Text color classes for compound badge text style defp text_color_class(:primary), do: "text-primary" defp text_color_class(:secondary), do: "text-secondary" defp text_color_class(:accent), do: "text-accent" defp text_color_class(:info), do: "text-info" defp text_color_class(:success), do: "text-success" defp text_color_class(:warning), do: "text-warning" defp text_color_class(:error), do: "text-error" defp text_color_class(:neutral), do: "text-neutral" defp text_color_class(:base), do: "text-base-content" defp text_color_class("primary"), do: "text-primary" defp text_color_class("secondary"), do: "text-secondary" defp text_color_class("accent"), do: "text-accent" defp text_color_class("info"), do: "text-info" defp text_color_class("success"), do: "text-success" defp text_color_class("warning"), do: "text-warning" defp text_color_class("error"), do: "text-error" defp text_color_class("neutral"), do: "text-neutral" defp text_color_class("base"), do: "text-base-content" defp text_color_class(_), do: "text-base-content" # Block color classes (background + text) for compound badge blocks style defp block_color_class(:primary), do: "bg-primary text-primary-content" defp block_color_class(:secondary), do: "bg-secondary text-secondary-content" defp block_color_class(:accent), do: "bg-accent text-accent-content" defp block_color_class(:info), do: "bg-info text-info-content" defp block_color_class(:success), do: "bg-success text-success-content" defp block_color_class(:warning), do: "bg-warning text-warning-content" defp block_color_class(:error), do: "bg-error text-error-content" defp block_color_class(:neutral), do: "bg-neutral text-neutral-content" defp block_color_class(:base), do: "bg-base-300 text-base-content" defp block_color_class("primary"), do: "bg-primary text-primary-content" defp block_color_class("secondary"), do: "bg-secondary text-secondary-content" defp block_color_class("accent"), do: "bg-accent text-accent-content" defp block_color_class("info"), do: "bg-info text-info-content" defp block_color_class("success"), do: "bg-success text-success-content" defp block_color_class("warning"), do: "bg-warning text-warning-content" defp block_color_class("error"), do: "bg-error text-error-content" defp block_color_class("neutral"), do: "bg-neutral text-neutral-content" defp block_color_class("base"), do: "bg-base-300 text-base-content" defp block_color_class(_), do: "bg-base-300 text-base-content" # Dot color classes for compound badge dots style defp dot_color_class_for_segment(:primary), do: "bg-primary" defp dot_color_class_for_segment(:secondary), do: "bg-secondary" defp dot_color_class_for_segment(:accent), do: "bg-accent" defp dot_color_class_for_segment(:info), do: "bg-info" defp dot_color_class_for_segment(:success), do: "bg-success" defp dot_color_class_for_segment(:warning), do: "bg-warning" defp dot_color_class_for_segment(:error), do: "bg-error" defp dot_color_class_for_segment(:neutral), do: "bg-neutral" defp dot_color_class_for_segment(:base), do: "bg-base-300" defp dot_color_class_for_segment("primary"), do: "bg-primary" defp dot_color_class_for_segment("secondary"), do: "bg-secondary" defp dot_color_class_for_segment("accent"), do: "bg-accent" defp dot_color_class_for_segment("info"), do: "bg-info" defp dot_color_class_for_segment("success"), do: "bg-success" defp dot_color_class_for_segment("warning"), do: "bg-warning" defp dot_color_class_for_segment("error"), do: "bg-error" defp dot_color_class_for_segment("neutral"), do: "bg-neutral" defp dot_color_class_for_segment("base"), do: "bg-base-300" defp dot_color_class_for_segment(_), do: "bg-base-300" @doc """ Renders a presence indicator showing user count. """ attr :count, :integer, default: 0 attr :show_text, :boolean, default: false attr :class, :string, default: "" def presence_indicator(assigns) do ~H""" <%= if @count > 0 do %> <%= if @show_text do %> {@count} <% end %> <% end %> """ end end